Applied Programming/Lists and Tuples/JavaScript

arrays.js

edit
/* """This program demonstrates file, list, and tuple processing.

It creates a temporary file, adds data to the file, and reads the file
into an array of arrays. It then provides a menu of options for displaying 
and searching the file data.

It will not run if the file already exists.

Input:
    None

Output:
    A temporary file and file contents.

References:

*/

const fs = require("fs");

if (typeof module != "undefined" && !module.parent) {
    main();
}

/**
  * Runs the main program logic.
  */
function main()
{
    let filename = "~temperatures.txt";

    if(fileExists(filename))
    {
        console.log(`File already exists: ${filename}`)
        process.exit(1)
    }

    createFile(filename);
    let temperatures = readFile(filename);
    deleteFile(filename);

    while (true) {
        let choice = getChoice();
        switch (choice) {
            case "1":
                displayTemperatures(temperatures, "Celsius")
                break;
            case "2":
                displayTemperatures(temperatures, "Fahrenheit")
                break;
            case "3":
                searchTemperatures(temperatures, "Celsius")
                break;
            case "4":
                searchTemperatures(temperatures, "Fahrenheit")
                break
            default:
                return;
        }    
    }
}

/**
 * Creates a text file.
 * 
 * @param Text filename to create.
 */
function createFile(filename)
{
    let data = '"C","F"\n';
    for(let celsius = 0; celsius <= 100; celsius += 10)
    {
        let fahrenheit = celsius * 9 / 5 + 32;
        data += `${celsius.toFixed(1)},${fahrenheit.toFixed(1)}\n`;
    }

    try {
        fs.writeFileSync(filename, data);
    } catch (error) {
        console.error(error);
    }
}

/**
 * Reads a text file.
 * 
 * File must be formatted as CSV with:
 * "C","F"
 * number,number
 * 
 * @param Text filename to read
 * @returns array of arrays
 * @throws RangeError if file format is invalid
 */
function readFile(filename)
{
    try {
        let data = fs.readFileSync(filename, "utf-8");
        let lines = data.trim().split("\n");
        
        let header = lines[0];
        if (header != '"C","F"') {
            throw new RangeError(`Invalid header format found in ${filename}: ${header}`)
        }

        lines.shift();
        let temperatures = [];
        for(const line of lines) {
            let row = line.split(",");
            if (row.length != 2 || isNaN(row[0]) || isNaN(row[1])) {
                throw new RangeError(`Invalid data format found in ${filename}: ${row}`)
            }

            row[0] = Number(row[0]);
            row[1] = Number(row[1]);
            temperatures.push(row);
        }

        return temperatures;
    } catch (error) {
        console.error(error);
        process.exit(2)
    }
}

/**
 * Deletes a file.
 * 
 * @param Text filename to delete.
 */
function deleteFile(filename)
{
    try {
        fs.unlinkSync(filename);
    } catch (error) {
        console.error(error);
    }
}

/**
 * Checks to see if a file exists.
 * 
 * @param Text filename to check.
 * @returns true if exists or false if not.
 */
function fileExists(filename)
{
    return fs.existsSync(filename);
}

/**
 * Input function to get input in Node environment.
 * 
 * @param {string} text prompt
 * @returns {string} input
 */
 function prompt(text) {
    const rls = require('readline-sync');
    let value = rls.question(text);
    return value;
}

/**
 * Displays menu and gets user choice.
 * 
 * @returns text choice or empty string.
 */
function getChoice() {
    const menu = "Select from the following options or press <Enter> to quit:\n" +
        "1. Display table sorted by Celsius temperature.\n" +
        "2. Display table sorted by Fahrenheit temperature.\n" +
        "3. Search for Celsius temperaturen.\n" +
        "4. Search for Fahrenheit temperature.\n";

    while (true) {
        console.log(menu);
        let choice = prompt("Enter choice: ");
        console.log("");
        if (choice === "") {
            return choice;
        }

        if (choice.length == 1 && "1234".includes(choice)) {
            return choice;
        }

        console.log(`${choice} is not a valid choice.\n`);        
    }
}

/**
 * Displays temperature array.
 * 
 * @param array temperatures.
 * @param scale "Celsius" or "Fahrenheit"
 * @throws RangeError if scale is invalid
 */
function displayTemperatures(temperatures, scale) {
    let firstColumn = undefined;
    let secondColumn = undefined;

    switch (scale) {
        case "Celsius":
            temperatures.sort(compareCelsius);
            console.log("C\tF");
            firstColumn = 0;
            secondColumn = 1;
            break;
        case "Fahrenheit":
            console.log("F\tC");
            firstColumn = 1;
            secondColumn = 0;
            break;
        default:
            throw new RangeError("Scale must be Celsius or Fahrenheit");
    }

    for(const row of temperatures) {
        console.log(`${row[firstColumn]}\t${row[secondColumn]}`);
    }

    console.log("");
}

/**
 * Get temperature to search for.
 * 
 * @param scale "Celsius" or "Fahrenheit"
 * @throws RangeError if scale is invalid
 * @returns Number or empty string
 */
function getTemperature(scale) {
    if (!["Celsius", "Fahrenheit"].includes(scale)) {
        throw new RangeError("Scale must be Celsius or Fahrenheit");
    }

    let temperature = prompt(`Enter ${scale} temperature: `);
    if (temperature == "") {
        return temperature;
    }

    if (isNaN(temperature)) {
        return "";
    }

    return Number(temperature);
}

/**
 * Searches temperature array to display nearest values.
 * 
 * @param array temperatures
 * @param scale "Celsius" or "Fahrenheit"
 * @throws RangeError if scale is invalid
 */
function searchTemperatures(temperatures, scale) {
    let searchElement = undefined;
    let displayElement = undefined;
    let otherScale = undefined;

    switch (scale) {
        case "Celsius":
            temperatures.sort(compareCelsius);
            searchElement = 0;
            displayElement = 1;
            otherScale = "Fahrenheit";
            break;
        case "Fahrenheit":
            temperatures.sort(compareFahrenheit);
            searchElement = 1;
            displayElement = 0;
            otherScale = "Celsius";
            break;
        default:
            throw new RangeError("Scale must be Celsius or Fahrenheit");
    }

    let temperature = getTemperature(scale);
    if (temperature === "") {
        return;
    }

    let last = temperatures[0];
    let row = undefined;
    for (row of temperatures) {
        if (temperature < row[searchElement]) {
            break;
        }
        last = row;
    }

    if (temperature < last[searchElement]) {
        console.log(`${temperature.toFixed(1)} ${scale} ` + 
            `is less than ${last[displayElement].toFixed(1)} ${otherScale}\n`)
    } else if (temperature == last[searchElement]) {
        console.log(`${temperature.toFixed(1)} ${scale} ` + 
            `is ${last[displayElement].toFixed(1)} ${otherScale}\n`)
    } else if (temperature > row[searchElement]) {
        console.log(`${temperature.toFixed(1)} ${scale} ` + 
            `is greater than ${last[displayElement].toFixed(1)} ${otherScale}\n`)
    } else {
        console.log(`${temperature.toFixed(1)} ${scale} ` + 
            `is between ${last[displayElement].toFixed(1)} ${otherScale} ` +
            `and ${row[displayElement].toFixed(1)} ${otherScale}\n`)
    }
}

/**
 * Compare temperature array elements for sort by Celsius.
 * 
 * @param a temperature element
 * @param b temperature element
 * @returns a - b
 */
function compareCelsius(a, b) {
    return Number(a[0]) - Number(b[0]);
}

/**
 * Compare temperature array elements for sort by Fahrenheit.
 * 
 * @param a temperature element
 * @param b temperature element
 * @returns a - b
 */
 function compareFahrenheit(a, b) {
    return Number(a[1]) - Number(b[1]);
}

Try It

edit

Copy and paste the code above into one of the following free online development environments or use your own JavaScript compiler / interpreter / IDE.

See Also

edit