Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save davidsierradz/0272b4eba8f9813309e6d0b4bf3b19ae to your computer and use it in GitHub Desktop.
Save davidsierradz/0272b4eba8f9813309e6d0b4bf3b19ae to your computer and use it in GitHub Desktop.
/**
* @license
* Copyright (c) 2018 David Balam Sierra DiazGranados.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Compares two arrays.
* From https://stackoverflow.com/a/10316616
*/
function compare(a, b) {
/*
Array-aware equality checker:
Returns whether arguments a and b are == to each other;
however if they are equal-lengthed arrays, returns whether their
elements are pairwise == to each other recursively under this
definition.
*/
if (a instanceof Array && b instanceof Array) {
if (a.length != b.length)
// assert same length
return false;
for (
var i = 0;
i < a.length;
i++ // assert each element equal
)
if (!compare(a[i], b[i])) return false;
return true;
} else {
return a == b; // if not both arrays, should be the same
}
}
/**
* Returns a closure that follows a seeded pseudo-random number generator.
* Inspired by: https://stackoverflow.com/a/19303725
*
* @param {Number} firstSeed A seed.
*
* @return {Function}
*/
const randomWithSeed = firstSeed => {
let seed = firstSeed;
return function(top) {
var x = Math.sin(seed++) * 10000;
return Math.floor((x - Math.floor(x)) * top) + 1;
};
};
const test_randomWithSeed = () => {
console.assert(
(() => {
const testArray = [8, 10, 3, 10, 8, 9, 9, 6, 2, 8];
const randomFunction = randomWithSeed(1);
const randomArray = Array.from(Array(10).keys(), x => randomFunction(10));
return compare(testArray, randomArray);
})(),
'randomWithSeed Failed.',
);
};
/**
* Shuffles an array with a Fisher–Yates shuffle algorithm.
* Inspired by: https://stackoverflow.com/a/6274381
*
* @param {Array} a An array containing the items.
* @param {Boolean} seeded Determines if the pseudo-random is seeded.
* @param {Number} seed A seed.
*
* @return {Array}
*/
const shuffleArray = (a, seeded = false, seed = 1) => {
let randomNumberGenerator;
if (seeded) {
randomNumberGenerator = randomWithSeed(seed);
} else {
randomNumberGenerator = top => Math.floor(Math.random() * (top + 1));
}
for (let i = a.length - 1; i > 0; i--) {
const j = randomNumberGenerator(i);
[a[i], a[j]] = [a[j], a[i]];
}
return a;
};
const test_shuffleArray = () => {
console.assert(
(() => {
const testArray = [1, 2, 10, 4, 6, 5, 7, 3, 9, 8];
const unorderedArray = shuffleArray(
Array.from(Array(10).keys(), x => x + 1),
true,
);
return compare(testArray, unorderedArray);
})(),
'shuffleArray Failed.',
);
};
/**
* Generates an array of random numbers.
*
* @param {Number} N The array length.
* @param {Boolean} seeded Determines if the pseudo-random is seeded.
* @param {Number} seed A seed.
*
* @return {Array}
*/
const generateRandomArrayOfNumbers = (N, seeded = false, seed = 1) => {
const numbersArray = Array.from(Array(N).keys(), x => x + 1);
return shuffleArray(numbersArray, seeded, seed);
};
/**
* Makes a Generator to iterate over an array, returns a slice with a step length.
*
* @param {Array} array The array to iterate.
* @param {Number} step The array chunk length.
*
* @return {Object} An Iterator protocol based generator.
*/
function* makeGetNFromArrayGenerator(array, step) {
const max = array.length;
let current = 0;
while (current < max) {
yield array.slice(current, current + step);
current += step;
}
}
/**
* Generates an array of arrays (Matrix) of random numbers.
*
* @param {Number} N The matrix rows length.
* @param {Number} M The matrix columns length.
* @param {Boolean} seeded Determines if the pseudo-random is seeded.
* @param {Number} seed A seed.
*
* @return {Array}
*/
const generateMatrix = (N, M, seeded = false, seed = 1) => {
let randomArray = generateRandomArrayOfNumbers(N * M, seeded, seed);
let randomArrayIterator = makeGetNFromArrayGenerator(randomArray, M);
let matrix = Array.from(
{ length: N },
() => randomArrayIterator.next().value,
);
return matrix;
};
const test_generateMatrix = () => {
console.assert(
(() => {
const testMatrix = [[1, 2, 9], [4, 5, 6], [3, 8, 7]];
const randomMatrix = generateMatrix(3, 3, true);
return compare(testMatrix, randomMatrix);
})(),
'generateMatrix Failed.',
);
};
/**
* Returns a column from a matrix.
*
* @param {Array} matrix The matrix.
* @param {Number} M The matrix column.
*
* @return {Array}
*/
const getColumnFromMatrix = (matrix, M = 0) => {
return matrix.map(e => e[M]);
};
const test_getColumnFromMatrix = () => {
console.assert(
(() => {
const testMatrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const firstColumn = [1, 4, 7];
return compare(firstColumn, getColumnFromMatrix(testMatrix));
})(),
'getColumnFromMatrix Failed.',
);
};
/**
* Returns a list of even columns in a matrix.
*
* @param {Array} matrix The matrix.
*
* @return {Array}
*/
const getEvenColumnsFromMatrix = matrix => {
return matrix[0]
.map((e, i) => (i % 2 === 0 ? i : null))
.filter(e => e !== null)
.map(i => getColumnFromMatrix(matrix, i));
};
const test_getEvenColumnsFromMatrix = () => {
console.assert(
(() => {
const testMatrix = [[5, 3, 8], [1, 2, 4], [9, 7, 6]];
const evenColumns = [[5, 1, 9], [8, 4, 6]];
return compare(evenColumns, getEvenColumnsFromMatrix(testMatrix));
})(),
'getEvenColumnsFromMatrix Failed.',
);
};
/**
* Returns the average of the matrix numbers.
*
* @param {Array} matrix The matrix.
*
* @return {Number} The Average.
*/
const getAverageFromMatrix = matrix => {
return (
matrix.reduce(
(total, column) => (total += column.reduce((a, b) => a + b)),
0,
) / matrix.length
);
};
const test_getAverageFromMatrix = () => {
console.assert(
(() => {
const testMatrix = [[5, 1, 9], [8, 4, 6]];
return 16.5 === getAverageFromMatrix(testMatrix);
})(),
'getAverageFromMatrix Failed.',
);
};
/**
* Returns an array with all matrix column sums.
*
* @param {Array} matrix The matrix.
*
* @return {Array}
*/
const getMatrixColumnsSum = matrix => {
return matrix[0]
.map((e, i) => getColumnFromMatrix(matrix, i))
.map(column => column.reduce((a, b) => a + b));
};
const test_getMatrixColumnsSum = () => {
console.assert(
(() => {
const testMatrix = [[5, 3, 8], [1, 2, 4], [9, 7, 6]];
const columnsSumTotals = [15, 12, 18];
return compare(columnsSumTotals, getMatrixColumnsSum(testMatrix));
})(),
'getMatrixColumnsSum Failed.',
);
};
/**
* Returns an array with the sums that are more than average.
*
* @param {Array} matrixColumnsSums The sums of matrix columns.
* @param {Number} average The average to compare.
*
* @return {Array}
*/
const getMatrixColumnsHigherThanAverage = (matrixColumnsSums, average) => {
return matrixColumnsSums.filter(sum => sum > average);
};
const test_getMatrixColumnsHigherThanAverage = () => {
console.assert(
(() => {
const testSums = [15, 12, 18];
return getMatrixColumnsHigherThanAverage(testSums, 16.5).length === 1;
})(),
'getMatrixColumnsHigherThanAverage Failed.',
);
};
/**
* The main function you probably want to run. <3
*
* @param {Number} N The matrix rows length.
* @param {Number} M The matrix columns length.
* @param {Boolean} printMatrix If you want to print the random generated matrix.
* @param {Boolean} seeded Determines if the pseudo-random is seeded.
* @param {Number} seed A seed.
*
* @return {Number} The number of columns that are more that the average of even colums.
*/
const main = (N, M, printMatrix = false, seeded = false, seed = 1) => {
if (N < 3 || M < 3) {
return 'Needs that arguments be at least 3 each.\n';
}
// Original matrix from challange (Toggle the sentence).
//const matrix = [[5, 3, 8], [1, 2, 4], [9, 7, 6]];
const matrix = generateMatrix(N, M, seeded, seed);
if (printMatrix) {
console.log(matrix);
}
return getMatrixColumnsHigherThanAverage(
getMatrixColumnsSum(matrix),
getAverageFromMatrix(getEvenColumnsFromMatrix(matrix)),
).length;
};
// Example of a run.
//console.log(main(3, 3, true, true, 200));
// Uncomment to run all tests.
//test_randomWithSeed();
//test_shuffleArray();
//test_generateMatrix();
//test_getColumnFromMatrix();
//test_getEvenColumnsFromMatrix();
//test_getAverageFromMatrix();
//test_getMatrixColumnsSum();
//test_getMatrixColumnsHigherThanAverage();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment