Factorializing a number with .reduce() - javascript

I am trying to write a function that will produce the factorial of a provided integer and then reduce the factorial array (by multiplying each array element).
For example:
factor(5) >>> [1, 2, 3, 4, 5] >>> 1 * 2 * 3 * 4 * 5 >>> 120
var array = [ ];
function factor(num) {
for (i = 1; i <= num; i++) {
array.push(i);
}
array.reduce(function(a, b) {
return a * b;
})
};
factor(5);
However, it keeps returning undefined.
I think it has to do with the formatting of the function, but I'm not sure.

Try to pass the initial value for reduce,
array.reduce(function(a, b) {
return a * b;
},1);
Also return the reduced value of the array from the function,
function factor(num) {
for (i = 1; i <= num; i++) {
array.push(i);
}
return array.reduce(function(a, b) {
return a * b;
},1)
};
console.log(factor(5));

Your problem that your function does not actually return any value, and the "return" value of such a function is undefined. Let's look at why this is happening:
function factor(num) {
for (i = 1; i <= num; i++) {
array.push(i);
}
array.reduce(function(a, b) {
return a * b; // <-- Here is probably your misunderstanding
});
};
That return that I marked returns from the function that you pass to reduce(), but there is no return from factor().

.reduce() is not necessary to return expected results. Try utilizing single for loop
var array = [];
function factor(num) {
for (var i = 1, res = 1; i < num; array[i - 1] = i, res *= ++i);
return res
};
console.log(
factor(3)
, factor(4)
, factor(5)
, factor(6)
, array
)

using Array indexes and reduce if anybody doesnt want to fill their arrays with ordered numbers.
num = 10;
Array(num).fill(null).reduce((acc, val, i) => {
if (i == 0) {
return 1;
}
return acc * (i + 1);
}, 1)

function factor(num) {
return Array(num)
.fill(null)
.map((item, index) => index + 1)
.reduce((pv, cv) => pv * cv);
}
console.log(factor(3), factor(4), factor(5), factor(6));

Related

JavaScript: Higher Order Function that Calls Add Function to Return New Array; Error: 'NaN' elements in output array

I have a function 'sometimes' and want to return a function object from it.
Below is my code:
let add = (a, b) => {
return a + b;
};
myFunc = sometimes(add);
const outputArr = [];
for (let i = 0; i < 3; i++) {
outputArr.push(myFunc(2 + i, 3 + i));
}
function sometimes (inputFunc){
return function (a, b){
return inputFunc()
}
}
outputArr
I expect my outputArr variable to equal:
[5, 7, 9]
Instead mine equals:
[ NaN, NaN, NaN ]
What am I doing wrong?
You are not passing the parameters to the wrapped function. The add function tries to sum two undefined values and the result is NaN (not a number).
You have to pass the parameters to the wrapped function:
return function(a, b) {
return inputFunc(a, b); // <<<
}
Since sometimes is a higher order function, that needs to wrap different functions, with a changing number of parameters, it can't know the implementation of the wrapped function. To ensure that, you should use rest parameters (to collect the parameters to an array) and spread (to convert the array back to parameters) to pass the arguments to the wrapped function.
let add = (a, b) => {
return a + b;
};
myFunc = sometimes(add);
const outputArr = [];
for (let i = 0; i < 3; i++) {
outputArr.push(myFunc(2 + i, 3 + i));
}
function sometimes(inputFunc) {
return function(...args) {
return inputFunc(...args)
}
}
console.log(outputArr);
you can use your code as
function sometimes(a,b){
return a + b;
}
const outputArr = [];
for (let i = 0; i < 3; i++) {
outputArr.push(sometimes(2 + i, 3 + i));
}
console.log(outputArr);
now the output is
[ 5, 7, 9 ]

Calculating median - javascript

I've been trying to calculate median but still I've got some mathematical issues I guess as I couldn't get the correct median value and couldn't figure out why. Here's the code;
class StatsCollector {
constructor() {
this.inputNumber = 0;
this.average = 0;
this.timeout = 19000;
this.frequencies = new Map();
for (let i of Array(this.timeout).keys()) {
this.frequencies.set(i, 0);
}
}
pushValue(responseTimeMs) {
let req = responseTimeMs;
if (req > this.timeout) {
req = this.timeout;
}
this.average = (this.average * this.inputNumber + req) / (this.inputNumber + 1);
console.log(responseTimeMs / 1000)
let groupIndex = Math.floor(responseTimeMs / 1000);
this.frequencies.set(groupIndex, this.frequencies.get(groupIndex) + 1);
this.inputNumber += 1;
}
getMedian() {
let medianElement = 0;
if (this.inputNumber <= 0) {
return 0;
}
if (this.inputNumber == 1) {
return this.average
}
if (this.inputNumber == 2) {
return this.average
}
if (this.inputNumber > 2) {
medianElement = this.inputNumber / 2;
}
let minCumulativeFreq = 0;
let maxCumulativeFreq = 0;
let cumulativeFreq = 0;
let freqGroup = 0;
for (let i of Array(20).keys()) {
if (medianElement <= cumulativeFreq + this.frequencies.get(i)) {
minCumulativeFreq = cumulativeFreq;
maxCumulativeFreq = cumulativeFreq + this.frequencies.get(i);
freqGroup = i;
break;
}
cumulativeFreq += this.frequencies.get(i);
}
return (((medianElement - minCumulativeFreq) / (maxCumulativeFreq - minCumulativeFreq)) + (freqGroup)) * 1000;
}
getAverage() {
return this.average;
}
}
Here's the snapshot of the results when I enter the values of
342,654,987,1093,2234,6243,7087,20123
The correct result should be;
Median: 1663.5
Change your median method to this:
function median(values){
if(values.length ===0) throw new Error("No inputs");
values.sort(function(a,b){
return a-b;
});
var half = Math.floor(values.length / 2);
if (values.length % 2)
return values[half];
return (values[half - 1] + values[half]) / 2.0;
}
fiddle
Here's another solution:
function median(numbers) {
const sorted = Array.from(numbers).sort((a, b) => a - b);
const middle = Math.floor(sorted.length / 2);
if (sorted.length % 2 === 0) {
return (sorted[middle - 1] + sorted[middle]) / 2;
}
return sorted[middle];
}
console.log(median([4, 5, 7, 1, 33]));
The solutions above - sort then find middle - are fine, but slow on large data sets. Sorting the data first has a complexity of n x log(n).
There is a faster median algorithm, which consists in segregating the array in two according to a pivot, then looking for the median in the larger set. Here is some javascript code, but here is a more detailed explanation
// Trying some array
alert(quickselect_median([7,3,5])); // 2300,5,4,0,123,2,76,768,28]));
function quickselect_median(arr) {
const L = arr.length, halfL = L/2;
if (L % 2 == 1)
return quickselect(arr, halfL);
else
return 0.5 * (quickselect(arr, halfL - 1) + quickselect(arr, halfL));
}
function quickselect(arr, k) {
// Select the kth element in arr
// arr: List of numerics
// k: Index
// return: The kth element (in numerical order) of arr
if (arr.length == 1)
return arr[0];
else {
const pivot = arr[0];
const lows = arr.filter((e)=>(e<pivot));
const highs = arr.filter((e)=>(e>pivot));
const pivots = arr.filter((e)=>(e==pivot));
if (k < lows.length) // the pivot is too high
return quickselect(lows, k);
else if (k < lows.length + pivots.length)// We got lucky and guessed the median
return pivot;
else // the pivot is too low
return quickselect(highs, k - lows.length - pivots.length);
}
}
Astute readers will notice a few things:
I simply transliterated Russel Cohen's Python solution into JS,
so all kudos to him.
There are several small optimisations worth
doing, but there's parallelisation worth doing, and the code as is
is easier to change in either a quicker single-threaded, or quicker
multi-threaded, version.
This is the average linear time
algorithm, there is more efficient a deterministic linear time version, see Russel's
post for details, including performance data.
ADDITION 19 Sept. 2019:
One comment asks whether this is worth doing in javascript. I ran the code in JSPerf and it gives interesting results.
if the array has an odd number of elements (one figure to find), sorting is 20% slower that this "fast median" proposition.
if there is an even number of elements, the "fast" algorithm is 40% slower, because it filters through the data twice, to find elements number k and k+1 to average. It is possible to write a version of fast median that doesn't do this.
The test used rather small arrays (29 elements in the jsperf test). The effect appears to be more pronounced as arrays get larger. A more general point to make is: it shows these kinds of optimisations are worth doing in Javascript. An awful lot of computation is done in JS, including with large amounts of data (think of dashboards, spreadsheets, data visualisations), and in systems with limited resources (think of mobile and embedded computing).
var arr = {
max: function(array) {
return Math.max.apply(null, array);
},
min: function(array) {
return Math.min.apply(null, array);
},
range: function(array) {
return arr.max(array) - arr.min(array);
},
midrange: function(array) {
return arr.range(array) / 2;
},
sum: function(array) {
var num = 0;
for (var i = 0, l = array.length; i < l; i++) num += array[i];
return num;
},
mean: function(array) {
return arr.sum(array) / array.length;
},
median: function(array) {
array.sort(function(a, b) {
return a - b;
});
var mid = array.length / 2;
return mid % 1 ? array[mid - 0.5] : (array[mid - 1] + array[mid]) / 2;
},
modes: function(array) {
if (!array.length) return [];
var modeMap = {},
maxCount = 1,
modes = [array[0]];
array.forEach(function(val) {
if (!modeMap[val]) modeMap[val] = 1;
else modeMap[val]++;
if (modeMap[val] > maxCount) {
modes = [val];
maxCount = modeMap[val];
}
else if (modeMap[val] === maxCount) {
modes.push(val);
maxCount = modeMap[val];
}
});
return modes;
},
variance: function(array) {
var mean = arr.mean(array);
return arr.mean(array.map(function(num) {
return Math.pow(num - mean, 2);
}));
},
standardDeviation: function(array) {
return Math.sqrt(arr.variance(array));
},
meanAbsoluteDeviation: function(array) {
var mean = arr.mean(array);
return arr.mean(array.map(function(num) {
return Math.abs(num - mean);
}));
},
zScores: function(array) {
var mean = arr.mean(array);
var standardDeviation = arr.standardDeviation(array);
return array.map(function(num) {
return (num - mean) / standardDeviation;
});
}
};
2022 TypeScript Approach
const median = (arr: number[]): number | undefined => {
if (!arr.length) return undefined;
const s = [...arr].sort((a, b) => a - b);
const mid = Math.floor(s.length / 2);
return s.length % 2 === 0 ? ((s[mid - 1] + s[mid]) / 2) : s[mid];
};
Notes:
The type in the function signature (number[]) ensures only an array of numbers can be passed to the function. It could possibly be empty though.
if (!arr.length) return undefined; checks for the possible empty array, which would not have a median.
[...arr] creates a copy of the passed-in array to ensure we don't overwrite the original.
.sort((a, b) => a - b) sorts the array of numbers in ascending order.
Math.floor(s.length / 2) finds the index of the middle element if the array has odd length, or the element just to the right of the middle if the array has even length.
s.length % 2 === 0 determines whether the array has an even length.
(s[mid - 1] + s[mid]) / 2 averages the two middle items of the array if the array's length is even.
s[mid] is the middle item of an odd-length array.
TypeScript Answer 2020:
// Calculate Median
const calculateMedian = (array: Array<number>) => {
// Check If Data Exists
if (array.length >= 1) {
// Sort Array
array = array.sort((a: number, b: number) => {
return a - b;
});
// Array Length: Even
if (array.length % 2 === 0) {
// Average Of Two Middle Numbers
return (array[(array.length / 2) - 1] + array[array.length / 2]) / 2;
}
// Array Length: Odd
else {
// Middle Number
return array[(array.length - 1) / 2];
}
}
else {
// Error
console.error('Error: Empty Array (calculateMedian)');
}
};
const median = (arr) => {
return arr.slice().sort((a, b) => a - b)[Math.floor(arr.length / 2)];
};
Short and sweet.
Array.prototype.median = function () {
return this.slice().sort((a, b) => a - b)[Math.floor(this.length / 2)];
};
Usage
[4, 5, 7, 1, 33].median()
Works with strings as well
["a","a","b","b","c","d","e"].median()
For better performance in terms of time complexity, use MaxHeap - MinHeap to find the median of stream of array.
Simpler & more efficient
const median = dataSet => {
if (dataSet.length === 1) return dataSet[0]
const sorted = ([ ...dataSet ]).sort()
const ceil = Math.ceil(sorted.length / 2)
const floor = Math.floor(sorted.length / 2)
if (ceil === floor) return sorted[floor]
return ((sorted[ceil] + sorted[floor]) / 2)
}
Simple solution:
function calcMedian(array) {
const {
length
} = array;
if (length < 1)
return 0;
//sort array asc
array.sort((a, b) => a - b);
if (length % 2) {
//length of array is odd
return array[(length + 1) / 2 - 1];
} else {
//length of array is even
return 0.5 * [(array[length / 2 - 1] + array[length / 2])];
}
}
console.log(2, calcMedian([1, 2, 2, 5, 6]));
console.log(3.5, calcMedian([1, 2, 2, 5, 6, 7]));
console.log(9, calcMedian([13, 9, 8, 15, 7]));
console.log(3.5, calcMedian([1, 4, 6, 3]));
console.log(5, calcMedian([5, 1, 11, 2, 8]));
Simpler, more efficient, and easy to read
cloned the data to avoid alterations to the original data.
sort the list of values.
get the middle point.
get the median from the list.
return the median.
function getMedian(data) {
const values = [...data];
const v = values.sort( (a, b) => a - b);
const mid = Math.floor( v.length / 2);
const median = (v.length % 2 !== 0) ? v[mid] : (v[mid - 1] + v[mid]) / 2;
return median;
}
const medianArr = (x) => {
let sortedx = x.sort((a,b)=> a-b);
let halfIndex = Math.floor(sortedx.length/2);
return (sortedx.length%2) ? (sortedx[Math.floor(sortedx.length/2)]) : ((sortedx[halfIndex-1]+sortedx[halfIndex])/2)
}
console.log(medianArr([1,2,3,4,5]));
console.log(medianArr([1,2,3,4,5,6]));
function Median(arr){
let len = arr.length;
arr = arr.sort();
let result = 0;
let mid = Math.floor(len/2);
if(len % 2 !== 0){
result += arr[mid];
}
if(len % 2 === 0){
result += (arr[mid] + arr[mid+1])/2
}
return result;
}
console.log(`The median is ${Median([0,1,2,3,4,5,6])}`)
function median(arr) {
let n = arr.length;
let med = Math.floor(n/2);
if(n % 2 != 0){
return arr[med];
} else{
return (arr[med -1] + arr[med])/ 2.0
}
}
console.log(median[1,2,3,4,5,6]);
The arr.sort() method sorts the elements of an array in place and returns the array. By default, it sorts the elements alphabetically, so if the array contains numbers, they will not be sorted in numerical order.
On the other hand, the arr.sort((a, b) => a - b) method uses a callback function to specify how the array should be sorted. The callback function compares the two elements a and b and returns a negative number if a should be sorted before b, a positive number if b should be sorted before a, and zero if the elements are equal. In this case, the callback function subtracts b from a, which results in a sorting order that is numerical in ascending order.
So, if you want to sort an array of numbers in ascending order, you should use arr.sort((a, b) => a - b), whereas if you want to sort an array of strings alphabetically, you can use arr.sort():
function median(numbers) {
const sorted = Array.from(numbers).sort((a, b) => a - b);
const middle = Math.floor(sorted.length / 2);
if (sorted.length % 2 === 0) {
return (sorted[middle - 1] + sorted[middle]) / 2;
}
return sorted[middle];
}
function findMedian(arr) {
arr.sort((a, b) => a - b)
let i = Math.floor(arr.length / 2)
return arr[i]
}
let result = findMedian([0, 1, 2, 4, 6, 5, 3])
console.log(result)

Distributing array elements randomly to new arrays

I have an array of numbers from 1 to 60
var originalArray = [1, 2, 3, 4 .... 58, 59, 60] // etc
I want to - depending on another number between 2 and 4 - split those numbers randomly into the number of arrays specified, and for the result to be unique each and every time.
For example:
distributeArray(2) should result in two arrays, each with 30 numbers randomly selected from the original array.
distributeArray(3) should result in three arrays, each with 20 numbers randomly selected from original array.
I assume this is a reasonably common case so any pointers would be appreciated. Thanks in advance.
You could do something like this, first shuffle and then split array into n parts.
var arr = [...Array(61).keys()].slice(1)
function splitRandom(data, n) {
var seen = [];
var counter = 0;
var shuffle = data.reduce(function(r, e) {
function random() {
var rand = parseInt(Math.random(0, arr.length) * arr.length);
if (seen.indexOf(rand) != -1) {
return random()
} else {
seen.push(rand)
return rand;
}
}
r[random()] = e;
return r;
}, [])
var split = shuffle.reduce(function(r, e) {
var c = counter++;
r[c] = r[c].concat(e)
counter = counter % n;
return r;
}, Array(n).fill([]))
return split;
}
console.log(JSON.stringify(splitRandom(arr, 3)))
console.log(JSON.stringify(splitRandom(arr, 10)))
console.log(JSON.stringify(splitRandom(arr, 50)))
You can create a function which creates an array of n .length, and an array of x .length. Use do..while loop Array.prototype.splice() to remove a random index from originalArray, .push() the element to one of x random arrays, until originalArray.length evaluates to false, return array of arrays containing values.
const randomArrays = (n, x) => {
let [originalArray, result, len] = [
Array.from({length: n}, (_, key) => key)
, Array.from({length: x}, () => [])
, Math.ceil(n / x)
];
do {
let [curr, index] = [
originalArray
.splice(Math.floor(Math.random() * originalArray.length), 1)
.pop()
, Math.floor(Math.random() * result.length)
];
if (result[index].length < len)
result[index].push(curr);
else
for (let i = 0; i < result.length; i++) {
if (result[i].length < len) {
result[i].push(curr);
break;
}
}
} while (originalArray.length);
return result
}
console.log(
randomArrays(60, 3)
, randomArrays(21, 7)
, randomArrays(5, 3)
, randomArrays(27, 5)
);

Use reduce() method to find a skipped number in an array of consecutive numbers

I'm trying to use the reduce() method to find one skipped (missing) number in an array of (sometimes almost) consecutive numbers. Only one number will be missing at most.
This is my codepen: http://codepen.io/PiotrBerebecki/pen/zBrRVd
For example,
findMissing([1,2,3,5]) should return 4
findMissing([1,2,3,4]) should return undefined
findMissing([2,3,4,6]) should return 5
findMissing([2,4,5,6]) should return 3
The code that I developed seems to work fine if there is indeed a number that was skipped. But it returns an undesired value if all numbers are present. Would you know how to fix it?
My JS code:
function findMissing(arr) {
return arr.reduce(function(prev, curr) {
if (curr - prev !== 1) {
return curr - 1;
}
});
}
// This should return 4, and it indeed returns 4
console.log( findMissing([1,2,3,5]) );
// This should return 'undefined', but it returns 3
console.log( findMissing([1,2,3,4]) );
// This should return 5, and it indeed returns 5
console.log( findMissing([2,3,4,6]) );
UPDATE 1:
Based on the answers below, the following code delivers the desired outcome using the reduce() method:
// ****SOLUTION:****
function findMissing2(arr) {
return arr.reduce(function(prev, curr, index, array) {
if (curr === index + array[0]) {
return prev;
} else {
return index + array[0]++;
}
}, void 0);
}
console.log( findMissing2([1,2,3,4]) ); // Undefined
console.log( findMissing2([1,2,3,5]) ); // 4
console.log( findMissing3([2,3,4,6]) ); // 5
console.log( findMissing2([2,3,4,5]) ); // Undefined
console.log( findMissing2([2,4,5,6]) ); // 3
I would do this job as follows;
var a1 = [1,2,3,5],
a2 = [2,3,4,5],
a3 = [2,4,5,6],
res1 = a1.reduce((p,c,i,a) => c == i+a[0] ? p : i + a[0]++, void 0),
res2 = a2.reduce((p,c,i,a) => c == i+a[0] ? p : i + a[0]++, void 0),
res3 = a3.reduce((p,c,i,a) => c == i+a[0] ? p : i + a[0]++, void 0);
console.log(res1);
console.log(res2);
console.log(res3);
Note: void 0 is a very safe undefined value in JS. The above code will mutate the tested array. You might prefer to call like a1.slice().reduce... if you want to keep the tested array as it is.
Instead of reduce you should use for loop here
function findMissing(arr) {
var r = [];
for (var i = arr[0]; i <= arr[arr.length - 1]; i++) {
if (arr.indexOf(i) == -1) r.push(i);
}
return r;
}
console.log(findMissing([1, 2, 3, 5]));
console.log(findMissing([1, 3, 6]));
console.log(findMissing([10, 13, 16]));
Your reduce closure/callback function needs to return the value to be used as the next prev in the next iteration.
Because of this, in the second example, the first iteration returns undefined, as it does not enter the if block. The second iteration is passed the parameters of undefined, 3, where undefined - 3 !== 1 so it returns 2.
This propagates the way up your iterations, until it returns 3.
As such, I'm struggling to think of a way your reduce function could be adapted to correct this.
Perhaps using a simple for loop might be a bit more robust?
function findMissing(arr) {
for(var i = 1; i < arr.length; i++) {
if(arr[i] - arr[i-1] !== 1) {
return arr[i]-1;
}
}
}
As I said in comments, if you are looking for efficiency you could do it with recursion:
function findMissing(arr) {
if (arr.length === 1) return;
if(arr[1] - arr[0] !== 1){
return arr[0];
}
else{
return findMissing(arr.slice(1,arr.length));
}
}
Or even with a while loop:
function findMissing(arr) {
var i = 0;
while (arr[i+1] - arr[i] === 1) {
i++;
}
if (i < arr.length-1) return arr[i];
}
var findMissing = function (list) {
var expected_sum = (list[0] + list[list.length - 1]) * (list.length + 1) / 2;
var sum = list.reduce((a,b)=>a+b);
return expected_sum - sum;
}
console.log(findMissing([-5,-1,1,3,5,7,9,11]))

JavaScript - compare multiple arrays to one

I would like to output which of 'buns' and 'duns' has the most elements in common with 'me'. How should I do this?
var buns = ['bap', 'bun', 'bop'];
var duns = ['dap', 'dun', 'dop'];
var me = ['dap', 'bun', 'bop'];
reduce over the array to be tested and check if each element is in me.
function common(arr1, arr2) {
return arr2.reduce(function (p, c) {
if (arr1.indexOf(c) > -1) p++;
return p;
}, 0);
}
common(me, buns); // 2
common(me, duns); // 1
DEMO
Index important
function hamd(a, b) {
return a.reduce((sum, item, i) => {
if (item !== b[i]) return sum + 1;
return sum;
}, 0);
}
Index not important, duplicates not important
function diff(a, b) {
return a.reduce((sum, item, i) => {
if (b.indexOf(item) === -1) return sum + 1;
return sum;
}, 0);
}
Index not important, duplicates important
function diffU(a, b) {
b = b.slice();
return a.reduce((sum, item, i) => {
let i = b.indexOf(item);
if (i === -1) return sum + 1;
b.splice(i, 1);
return sum;
}, 0);
}
The one with the lowest score has the most similarity, e.g.
diff(me, buns) // 1
diff(me, duns) // 2
// `buns` is more like `me` than `duns`
Please note that these are not commutative operations when the length of the Array is not the same; diff(a, b) may be different to diff(b, a) when a.length !== b.length
If you want to compare the results you need the common array on the same side of all tests

Categories

Resources