Applied Programming/Dictionaries and Sets/JavaScript
objects.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 objects. 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}`)
}
let record = {
C: Number(row[0]),
F: Number(row[1])
};
temperatures.push(record);
}
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 fields = undefined;
switch (scale) {
case "Celsius":
temperatures.sort(compareCelsius);
fields = ["C", "F"];
break;
case "Fahrenheit":
temperatures.sort(compareFahrenheit);
fields = ["F", "C"];
break;
default:
throw new RangeError("Scale must be Celsius or Fahrenheit");
}
console.log(`${fields[0]}\t${fields[1]}`);
for(const record of temperatures) {
console.log(`${record[fields[0]]}\t${record[fields[1]]}`);
}
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 = "C";
displayElement = "F";
otherScale = "Fahrenheit";
break;
case "Fahrenheit":
temperatures.sort(compareFahrenheit);
searchElement = "F";
displayElement = "C";
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.C) - Number(b.C);
}
/**
* 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.F) - Number(b.F);
}
Try It
editCopy and paste the code above into one of the following free online development environments or use your own JavaScript compiler / interpreter / IDE.