This repository has been archived on 2021-10-31. You can view files and clone it, but cannot push or open issues or pull requests.
SA3/hw2/Claudio_Maggioni/script.js
2019-10-28 08:35:04 +01:00

284 lines
8 KiB
JavaScript

/**
* JavaScript Exercise 1
* vim: set ts=2 sw=2 et tw=80:
*/
/**
* @param {number[]} a - The array of numbers.
* @param {number} c - The scalar multiplier.
* @return {number[]} An array computed by multiplying each element of the
* input array `a` with the input scalar value `c`.
*/
function scalar_product(a, c) {
if (!Array.isArray(a)) return undefined;
if (!c && c != 0) return a;
return a.map(e => e * c);
}
/**
* @param {number[]} a - The first array of numbers.
* @param {number[]} b - The second array of numbers.
* @return {number} A value computed by summing the products of each pair
* of elements of its input arrays `a`, `b` in the same position.
*/
function inner_product(a, b) {
if (a.length != b.length) return undefined;
return a.map((e, i) => e * b[i]).reduce((a, e) => a + e, 0);
}
/**
* @param {*[]} a - The array.
* @param {function} mapfn - The function for the map step.
* @param {function} [reducefn= function(x,y) { return x+y; }] - The
* function for the reduce step.
* @param {string} [seed=""] - The accumulator for the reduce step.
* @return {*} The reduced value after the map and reduce steps.
*/
function mapReduce(a, mapfn, reducefn, seed = "") {
if (!Array.isArray(a)) return undefined;
if (typeof mapfn != 'function') return undefined;
reducefn = reducefn || ((x, y) => x + y);
for (let i = 0; i < a.length; i++) {
seed = reducefn(seed, mapfn(a[i]));
}
return seed;
}
/**
* @param {number[]} a - The first sorted array of numbers.
* @param {number[]} b - The second sorted array of numbers.
* @return {number[]} A sorted array with all the elements from
* both `a` and `b`.
*/
function mergeSortedArrays(a, b) {
const m = new Array(a.length + b.length);
let ac = a.length - 1, bc = b.length - 1, i = ac + bc + 1;
while (i >= 0) {
if (ac < 0 || b[bc] > a[ac]) m[i--] = b[bc--];
else m[i--] = a[ac--];
}
return m;
}
/**
* @param {integer} x - The first integer.
* @param {integer} y - The second integer.
* @param {integer} [step=1] - The value to add at each step.
* @return {integer[]} An array containing numbers x, x+step, … last, where:
* - last equals x + n*step for some n,
* - last <= y < last + step if step > 0 and
* - last + step < y <= last if step < 0.
*/
function range(x, y, step = 1) {
if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(step)
|| step == 0) {
return undefined;
}
console.log(x, y, step);
if ((x > y && step > 0) || (x < y && step < 0)) {
return [];
}
const a = [];
while (x < y) {
a.push(x);
x += step;
}
return a;
}
/**
* @param {*[]} a - The array to flatten.
* @return {*[]} A flattened array.
*/
function flatten(arr) {
if (!Array.isArray(arr)) {
return arr;
}
const a = [];
arr.forEach(e => {
e = flatten(e); Array.isArray(e) ? a.push(...e) : a.push(e); });
return a;
}
/**
* @param {integer} [line_size=72] - The line size.
* @return {function} A function that takes a string as an argument
* and returns an array of strings where:
* a. each string length is no more than `line_size` and
* b. doesn't contain line breaks, tabs, double spaces and initial/trailing
* white spaces.
*/
function mkPrettyPrinter(line_size = 72) {
if (!Number.isFinite(line_size)) {
return undefined;
}
return (s) => {
if (typeof s !== 'string') {
return undefined;
}
s = s.replace('\n', ' ').trim().replace(/\s+/g, ' ');
const a = [];
let i = -1;
const words = s.split(' ');
for (const word of words) {
if (i == -1 || a[i].length + 1 + word.length > line_size) {
a[++i] = word;
} else {
a[i] += ' ' + word;
}
}
return a;
}
}
/**
* @param {integer} line_size - The line size.
* @param {integer} [level=0] level - The indentation level.
* @return {function} A function twith the following behavior:
* - If called with an integer `n`, change the indentation level by
* adding `n`to the current indentation level.
* - If called with `true`, return the current indentation level.
* - If called with a string:
* - break it into lines with length (after adding the indentation)
* no more than `line_size`,
* - add spaces in front of each line according to the current
* indentation level and
* - store the resulting lines internally.
* - [optional] If called with an array of strings, create an
* bullet list (using `*`) taking current indentation level into
* account. Also, each element should be properly broken into lines and indented.
* - If called with no arguments, produce an array with the lines stored so far.
* Internal storage must be emptied. Indentation level must not be changed.
*/
function mkIndenter(line_size, level=0) {
if (!Number.isFinite(line_size) || !Number.isFinite(level)) {
return undefined;
}
let state = [];
return (param) => {
if (Number.isInteger(param)) {
level += param;
} else if (param === true) {
return level;
} else if (typeof param === 'string') {
let words = mkPrettyPrinter(line_size - level)(param);
words = words.map(e => ' '.repeat(level) + e);
state.push(...words);
} else if (Array.isArray(param)) {
for (const e of param) {
if (typeof e !== 'string') {
return;
}
const words = mkPrettyPrinter(line_size - level - 2)(e);
state.push(' '.repeat(level) + '* ' + words[0]);
for (let i = 1; i < words.length; i++) {
state.push(' '.repeat(level + 2) + words[i]);
}
}
} else if (param === void(0)) {
const a = state;
state = [];
return a;
}
}
}
/**
* JavaScript Exercise 2
*/
/**
* Calculates the number of occurrences of letters in a given string
* @param {string} a - The input string.
* @return {number[]} An array indexed by the letter characters found in the string.
*/
function letter_frequency(s) {
if (typeof s !== 'string') {
return;
}
const a = [];
Array.from(s.toLowerCase()).forEach(c => a[c] = !a[c] ? 1 : a[c] + 1);
return a;
}
/**
* Displays the output of the letter frequency analysis in an HTML table
* generated within the `dom` element passed as parameter
* @param {number[]} a - The array indexed by the letter characters as returned
* from `letter_frequency()`.
* @param {Object} dom - The DOM element that will contain the resulting table.
* @return {undefined}
*/
function display_letter_frequency(a, dom) {
if (typeof a !== 'object' || typeof dom !== 'object' || !dom) {
return;
}
const t = document.createElement('table');
for (const x in a) {
const r = document.createElement('tr');
const letter = document.createElement('td');
const element = document.createElement('td');
r.appendChild(letter);
r.appendChild(element);
letter.innerText = x;
element.innerText = '' + a[x];
t.appendChild(r);
}
dom.innerHTML = t.outerHTML;
}
/**
* Links the provided input text field in the test page with the table.
* @param {Object} inputEl - The DOM object of the input element in test.html.
* @return {undefined}
*/
function online_frequency_analysis(inputEl) {
const a = letter_frequency(inputEl.value);
display_letter_frequency(a, document.getElementById('frequency_table'));
}
/**
* JavaScript Exercise 3
*/
function clock() {
const SECOND = 1000;
const MINUTE = SECOND * 60;
const HOUR = MINUTE * 60;
const digit = d => (d < 10 ? '0' : '') + d;
const format = (h, m, s) => digit(h) + ':' + digit(m) + ':' + digit(s);
function dateString(date) {
const epoch = Number.isInteger(date);
const h = epoch ? Math.floor(date / HOUR) : date.getHours();
const m = epoch ? Math.floor((date % HOUR) / MINUTE) : date.getMinutes();
const s = epoch ? Math.floor((date % MINUTE) / SECOND) : date.getSeconds();
return format(h, m, s);
}
const c = document.getElementById('clock');
let timer = false;
setInterval(() => {
d = new Date();
c.innerHTML = dateString(timer ? d - timer : d);
}, SECOND / 10);
return _ => timer = timer ? false : new Date();
}