Reduce over a single array summing slices - javascript

I have an array of values
let a = [1,2,3,4,5,6];
I want to sum specific slices, for example a.[0] + a.[1] giving a new array:
[1 + 2, 3 + 4, 5 + 6]
Is there a recommended way to do this with reduce() or other method? Such as some kind of stepping/range parameter?

Because I want #T.J. Crowder to be right :)
const a = [1, 2, 3, 4, 5, 6];
// Loop over all values of the array
const res = a.reduce((tmp, x, xi) => {
// Use Math.floor and xi (the index of the value we are treating)
// to store the values on the returned array at the correct position
tmp[Math.floor(xi / 2)] = (tmp[Math.floor(xi / 2)] || 0) + x;
return tmp;
}, []);
console.log(res);
Will also work if the number of element is not pair
const a = [1, 2, 3, 4, 5];
const res = a.reduce((tmp, x, xi) => {
tmp[Math.floor(xi / 2)] = (tmp[Math.floor(xi / 2)] || 0) + x;
return tmp;
}, []);
console.log(res);
Alternative solution :
const a = [1, 2, 3, 4, 5, 6];
const res = [];
do {
res.push(a.splice(0, 2).reduce((tmp, x) => tmp +x, 0));
} while (a.length);
console.log(res);

You can do this with reduce, but it's not the right tool for the job. Here's how, keying off index and passing an array around:
let array = [1,2,3,4,5,6];
let result = array.reduce((a, v, i) => {
if (i % 2 == 1) {
// It's an odd entry, so sum it with the
// previous entry and push to the result array
a.push(v + array[i - 1]);
}
return a;
}, []);
console.log(result);
You can squash that into a concise arrow function, at the expense of clarity:
let array = [1,2,3,4,5,6];
let result = array.reduce((a, v, i) => ((i % 2 === 1 ? a.push(v + array[i - 1]) : 0), a), []);
console.log(result);
A simple for loop would probably be more appropriate, though:
let array = [1,2,3,4,5,6];
let result = [];
for (let n = 0; n < array.length; n += 2) {
result.push(array[n] + array[n + 1]);
}
console.log(result);

Another approach with Array#flatMap and taking only the odd indices for a value.
var array = [1, 2, 3, 4, 5, 6],
result = array.flatMap((v, i, { [i + 1]: w = 0 }) => i % 2 ? [] : v + w);
console.log(result);

A simple and quick solution with [Array.prototype.reduce] can look like this:
const array = [1,2,3,4,5,6];
const range = 2;
const result = array.reduce((all, item, i) => {
const idx = Math.floor(i/range);
if (!all[idx]) all[idx] = 0;
all[idx] += item;
return all;
},[]);
console.log(result);

Related

Filter Specific Numbers and Sum Up

Given:
I have an array that looks like this:
[1, 1, 3, 3, 3, 2, 2, 1, 3, 3, 2, 3, 4, 2, 3, 4, 4, 2, 1, 3, 2, 4, 3, 2];
What I need:
scoreN = sum up all numbers with one
scoreST = sup all numbers with two
scoreO = sum up all numbers with three
scoreAA = sum up all numbers with four
totalScore = scoreN + scoreST + scoreO + scoreAA
Question:
What is the simplest (beginner friendly) JS code to filter the numbers and get the sum?
const array = [1, 1, 3, 3, 3, 2, 2, 1, 3, 3, 2, 3, 4, 2, 3, 4, 4, 2, 1, 3,2, 4, 3, 2];
Something like?
const scoreN = array.filter(1);
const scoreST = array.filter(2);
const scoreO = array.filter(3);
const scoreAA = array.filter(4);
const totalScore = scoreN + scoreST + scoreO + scoreAA
Your approach was quite correct.
But the array method filter takes a function which you can express with a lambda function x => x === 1 in which the argument x represents the current array value. The return value should be a boolean, in this case we want all numbers equal to 1.
The function reduce takes 2 arguments a function with the previous value and the current value and a default value if the array is empty. In this case 0 if there are no elements to sum up.
const numbers = [1, 1, 3, 3, 3, 2, 2, 1, 3, 3, 2, 3, 4, 2, 3, 4, 4, 2, 1, 3, 2, 4, 3, 2];
const sum = (a, b) => a + b;
const scoreN = numbers.filter(x => x === 1).reduce(sum, 0);
const scoreST = numbers.filter(x => x === 2).reduce(sum, 0);
const scoreO = numbers.filter(x => x === 3).reduce(sum, 0);
const scoreAA = numbers.filter(x => x === 4).reduce(sum, 0);
const total = scoreN + scoreST + scoreO + scoreAA;
console.log(total);
Yep, using filter you can filter the arrays down. However if you use reduce then you can filter and sum at the same time. E.g.:
const scoreN = numbers.reduce((sum, val) => {
if (val === 1) {
sum += val;
}
return sum;
}, 0);
The most beginner friendly code, that works the same for most c-like languages would be:
function score(array, value) {
let sum = 0;
for (let i = 0; i < array.length; i++) {
let element = array[i];
if (element === value) {
sum += element;
}
}
return sum;
}
another solutions that makes use of JS array functions would be:
function score(array, value) {
let sum = array
.filter(e => e === value)
.reduce((prev, curr) => prev + curr, 0);
return sum;
}
you would use both functions the same way:
const scoreN = score(array, 1);
const scoreST = score(array, 2);
const scoreO = score(array, 3);
const scoreAA = score(array, 4);
const totalScore = scoreN + scoreST + scoreO + scoreAA;

Mini-Max Sum In JavaScript - How to Get the Minimum Sum And Maximum Sum of 4 Elements in a 5-Element Array

Link to HackerRank Challenge
My idea is to loop through the array and sum all elements in the array except for one element each time, then find the smallest sum and the largest sum.
I know that .splice() can remove any element from an array. But currently, with my code, it's only removing one element from the array once. I.e. this is only giving me one chunk:
function miniMaxSum(arr) {
let smallestSum = 0;
let largestSum = 0;
for (let i = 0; i < arr.length; i++) {
let chunk = arr.splice(1);
console.log(chunk);
if (chunk > largestSum) largestSum = chunk;
if (chunk < smallestSum) smallestSum = chunk;
}
return (smallestSum, largestSum);
}
I need to remove one element from the array every time while looping, then get the max and min sums from that array.
So for given array of [1, 2, 3, 4, 5]
I should get the following possible "chunks":
[2, 3, 4, 5], [1, 3, 4, 5], [1, 2, 4, 5], [1, 2, 3, 5], [1, 2, 3, 4].
The chunk with the highest sum is [2, 3, 4, 5]
And the chunk with the smallest sum is [1, 2, 3, 4].
How can I adjust my code to get all of the possible 4-digit arrays within the given array so that I can compare their sums, still using a for-loop? Or if not with a for-loop, what else would you suggest?
EDIT: Now using Math.min() and Math.max() to get the smallest and largest elements in the array. Then using .filter() to remove those elements in order to create new arrays. Then getting the sums of those arrays.
function miniMaxSum(arr) {
let smallest = Math.min(...arr);
let largest = Math.max(...arr);
let smallestArray = arr.filter(element => element !== largest);
let largestArray = arr.filter(element => element !== smallest);
let sumOfSmallestArray = 0;
let sumOfLargestArray = 0;
for (let i = 0; i < smallestArray.length; i++) {
sumOfSmallestArray += smallestArray[i];
}
for (let i = 0; i < largestArray.length; i++) {
sumOfLargestArray += largestArray[i];
}
return ([sumOfSmallestArray, sumOfLargestArray]).toString();
}
But even though it works in my console, it doesn't work in HackerRank.
The key is to sort that array first, then the minimum will be the first element and the maximum will be the last, hence if you want to get the minimum set, it will be the array without the highest value (last element) and if you want to get the maximum set it will be the array without the lowest value (first element).
let data = [1, 3, 2, 4, 5];
// sort first
data = data.sort((a, b) => a - b);
// to get the sets only
let maxSet = data.slice(1);
let minSet = data.slice(0, -1);
console.log(minSet, maxSet);
// to get just the max/min value
const sum = data.reduce((a, total) => a + total, 0);
console.log(sum - data[data.length - 1], sum - data[0]);
The HackerRank challenge just asks for the sums of the, so you can make one pass through the array to calculate 3 facts:
Maximum element (a)
Minimum element (b)
Total sum of all elements (c)
The sum of the smallest chunk will be c - a and the sum of the largest will be c - b.
Here's a one-liner solution using reduce:
var arr = [1, 2, 3, 4, 5];
var [a, b, c] = arr.reduce(([a, b, c], x) => [a > x ? a : x, b < x ? b : x, c + x], [NaN, NaN, 0]);
console.log(c - a, c - b);
Note: the NaN's are just here to force the initial conditions (a > x/b < x to be false)
You could get the min and max values of the array and filter the array by taking not min or max value once.
var data = [1, 2, 3, 4, 5],
min = Math.min(...data),
max = Math.max(...data),
dataMin = data.filter(v => v !== min || !(min = -Infinity)),
dataMax = data.filter(v => v !== max || !(max = Infinity));
console.log(...dataMin);
console.log(...dataMax);
A more classical approach
function minMax(array) {
var min = array[0],
max = array[0],
sum = array[0],
i, v;
for (i = 1; i < array.length; i++) {
v = array[i];
sum += v;
if (v > max) max = v;
if (v < min) min = v;
}
console.log(sum - min, sum - max);
}
minMax([1, 2, 3, 4, 5]);
You can sort the array and for min take first four and add them and for max take last four and add them
let arr = [1, 2, 3, 4, 5]
let minAndMax = (arr) => {
arr = arr.sort((a,b) => a - b)
let op = {}
op.minArr = arr.slice(0,4)
op.min = op.minArr.reduce((a,b) => a+b, 0)
op.maxArr = arr.slice(arr.length-4,)
op.max = op.maxArr.reduce((a,b) => a + b ,0)
return op
}
console.log(minAndMax(arr))
This solution traverses the slice indexes, calculates the sum and when a maximum is found, it is put into result. Finally result is parsed:
var arr = [4, 8, 2, 6, 12];
var ln = arr.length;
var maxSum = undefined;
var result = "";
for (var splIndex = 0; splIndex < ln; splIndex++) {
var item = arr.splice(splIndex, 1);
var sum = 0;
for (var it of arr) sum += it;
if ((maxSum === undefined) || (maxSum < sum)) {
maxSum = sum;
result = JSON.stringify(arr);
}
arr.splice(splIndex, 0, item[0]);
}
console.log(JSON.parse(result));
EDIT
A simpler solution, of course is to find the minimum and calculate the sum without it.
The following function works:
function miniMaxSum(arr) {
var _arr = arr.sort((a, b) = > a - b)
var minVals = _arr.slice(0, 4)
var maxVals = _arr.slice(1)
const arrSum = __arr = > __arr.reduce((a, b) = > a + b, 0)
var minSum = arrSum(minVals)
var maxSum = arrSum(maxVals)
console.log(minSum, maxSum)
}
let arr = [15 ,12, 33, 25, 4];
//sort array
const arrSort = arr.sort((a,b)=> a-b );
console.log(arrSort);
//get values and sum
var max = arrSort.filter(value => value < Math.max(...arrSort)).reduce((ac,at)=>{
ac += at;
return ac;
},0);
var min = arrSort.filter(value => value > Math.min(...arrSort)).reduce((ac,at)=>{
ac += at;
return ac;
},0);
console.log(max);
console.log(min);
This worked for me.
let minValue, maxValue
const ascendingArray = arr.sort((a,b) => a - b)
const smallestNumber = ascendingArray[0]
const biggestNumber = ascendingArray[ascendingArray.length -1]
if(smallestNumber !== biggestNumber){
const biggestArray = arr.filter((number) => {
return number !== smallestNumber
})
const smallestArray = arr.filter((number) => {
return number !== biggestNumber
})
minValue = smallestArray.reduce((a,b) => a + b, 0)
maxValue = biggestArray.reduce((a,b) => a + b, 0)
console.log(minValue, maxValue);
}
else{
const arraySliced = arr.slice(0, 4)
const value = arraySliced.reduce((a,b) => a + b, 0)
console.log(value, value);
}
function miniMaxSum(arr) {
var soma = 0
let t = 0
for (var i = 0; i < arr.length; i++) {
soma += arr[i]
max = soma - arr[i]
}
let min = soma - arr[0]
return max + ' ' + min
}
console.log(miniMaxSum([7, 69, 2, 221, 8974]))
Here is a cleaner approach to solving this problem.
function miniMaxSum(arr) {
let min, max, sum, arrMin, arrMax; // declare variables
min = Math.min(...arr) // gets the smallest value from the arr
max = Math.max(...arr) // gets the largest number from the arr
sum = arr.reduce((a,b) => a+b, 0); // reduce used to add all values in arr
arrMin = sum - max; // excludes the largest value
arrMax = sum - min; // excludes the smallest value
console.log(arrMin+' '+arrMax) // output
}
easy solution
const miniMax = arr => {
let min = arr[0];
let max = arr[0];
for(let i = 0; i < arr.length; i++) {
if(arr[i] <= min) {
min = arr[i];
}
if (arr[i] >= max) {
max = arr[i];
}
}
let sum = arr.reduce((acc,curr) => acc + curr);
console.log(sum - max, sum - min);
}
miniMax([5,5,5,5,5]);
// result : 20 20
miniMax([1,2,3,4,5]);
// result : 10 14
I get Answer in very Simple way
function miniMaxSum(arr) {
let minval=arr[0];
let maxval=0;
let totalSum=0;
for(let i=0;i<arr.length;i++){
if (arr[i]>maxval){
maxval=arr[i];
}
if (arr[i]<minval){
minval=arr[i];
}
totalSum=totalSum+arr[i];
}
let minsum=totalSum - maxval;
let maxsum=totalSum - minval;
console.log( minsum,maxsum);
}
Use build Math methods to find max and min:
function miniMaxSum(arr) {
const min = Math.min(...arr);
const max = Math.max(...arr);
const sum = arr.reduce((a, b) => a + b);
console.log(sum - max, sum - min);
}

How can I sum all unique numbers of an array?

I've the following data:
var array = [2, 4, 12, 4, 3, 2, 2, 5, 0];
I want to sum 2 + 4 + 12 + 3 + 5 and want to show the result using JavaScript without any library, by simply using a for loop and if/else statements.
You can make use of ES6 Sets and .reduce() method of arrays:
let array = [2, 4, 12, 4, 3, 2, 2, 5, 0];
let sum = [...new Set(array)].reduce((a, c) => (a + c), 0);
console.log(sum);
you can try following using Set and Array.reduce
var array = [2,4,12,4,3,2,2,5,0];
let set = new Set();
let sum = array.reduce((a,c) => {
if(!set.has(c)) {set.add(c); a += c; }
return a;
}, 0);
console.log(sum);
const distinct = (array) =>
array ? array.reduce((arr, item) => (arr.find(i => i === item) ? [...arr] : [...arr, item]), []) : array;
const sum = distinct([2,4,12,4,3,2,2,5,0]).reduce((a,b) => a + b);
console.log(sum);
Here is a simple solution using a loop:
const array = [2, 4, 12, 4, 3, 2, 2, 5, 0];
function sumNotCommon(array) {
const sortedArray = array.slice().sort();
let sum = 0;
for (let i = 0; i < sortedArray.length; ++i) {
if (i === 0 || sortedArray[i] !== sortedArray[i-1])
sum += sortedArray[i];
}
return sum;
}
console.log(sumNotCommon(array));
First it sorts the array and then iterates through it ignoring equal numbers that follow each other.

Compounding values when mapping array?

I would like to compound values while mapping an array, I tried this but it didn't work:
var array = children.map((child, i) => {
return child.offsetHeight + array[i-1]
})
I would like an array that looks like this:
[1, 5, 3, 2]
to output:
[1, 6, 9, 11]
Using map is not a requirement. But I don't mind using something more intended than a for-loop.
Here an alternative way to other proposals and simple one-liner by using a forEach-loop:
let a = [1, 5, 3, 2],
b = [];
a.forEach((el, it) => { b.push(el + (b[it - 1] || 0)) });
console.log(b)
(b[it - 1] || 0) covers the first iteration where we would access b[-1]
You can use a combination of Array#map, Array#slice and Array#reduce :
.map( ... ) goes through your array
.slice( ... ) cuts a part from your array, from beginning to i+1
.reduce( ... ) returns the sum of the previously cut array
let children = [1, 5, 3, 2];
var array = children.map((child, i) =>
children.slice(0,i+1).reduce((acc, curr) => acc + curr, 0));
console.log(array);
This is one way:
const input = [1, 5, 3, 2];
const result = input.reduce((arr, x, i) =>
i == 0 ? [x] : [...arr, x + arr[arr.length - 1]]
, null)
console.log(result);
Reduce is better than map here, as you get access to the current state, rather than just the current item or the input array.
You can use array#reduce.
var result = [1, 5, 3, 2].reduce((r,v,i) => {
i ? r.push(r[i-1] + v) : r.push(v);
return r;
},[]);
console.log(result);
The easiest solution would be a combination of map slice and reduce:
arr = [1,5,3,2]
result = arr.map((elem, index) => arr.slice(0, index + 1).reduce((a,c) => a+c))
console.log(result)
You can do something like this, you must check at position 0 that array doesn't exist. This solution avoids using reduce and slice each step, improving performance;
var children = [1, 5, 3, 2]
var sum = 0;
var array = children.map((child, i, array) => {
sum = sum + child;
return sum;
})
console.log(array)
Example using for...of:
var arr = [1, 5, 3, 2]
var res = []
var c = 0
for (let item of arr) {
c += item
res.push(c)
}
console.log(res)
//[1, 6, 9, 11]
You could do this with reduce() method instead of map(). So if current index is not 0 you can take last element from accumulator and add current element.
const data = [1, 5, 3, 2]
const result = data.reduce((r, e, i) => {
r.push(i ? +r.slice(-1) + e : e)
return r;
}, []);
console.log(result)
You could also do this with just map() method using thisArg parameter and storing last value inside.
const data = [1, 5, 3, 2]
const result = data.map(function(e) {
return this.n += e
}, {n: 0});
console.log(result)
Or you could just create closure with IIFE and inside use map() method.
const data = [1, 5, 3, 2]
const result = (s => data.map(e => s += e))(0)
console.log(result)

Find a missing number in a sequence using .reduce

var o = [1,2,3,5,6,7,8]
var res = o.reduce(function(x,y){
return !((y-x)===1)?y-1:'Nothing'
})
console.log(res)//7
Output should be 4, want to know if it is possible using reduce or functionally (Not through loops)? it only works if the missing value is before the last value of an array.
You can use reduce to compute the actual sum of all elements and then subtract it from the target sum (n(a0+an)/2). This gives you the missing number.
var o = [1,2,3,5,6,7,8];
var len = o.length;
var sum = (len + 1) * (o[0] + o[len - 1]) / 2;
var res = sum - o.reduce((x,y) => x + y);
console.log(res);
Note that this works with any starting value and any step, e.g. for [3,5,7,11] it will correctly print 9. The only requirement is that o should be an arithmetic progression.
You could use a start value and check the previous element and the actual element.
var o = [1, 2, 3, 5, 6, 7, 8],
res = o.reduce(function(r, a, i, aa) {
return !i || r !== undefined || aa[i - 1] + 1 === a ? r : aa[i - 1] + 1;
}, undefined);
console.log(res);
Instead of reduce you could use find, which will not look any further once it finds a missing value:
const o = [1,2,3,5,6,7,8];
const res = o.find( (x,i) => o[i+1]-x > 1 ) + 1;
console.log(res)//4
It's always good to generalize these jobs. So you should provide a series descriptor function for the algorithm to find which item is missing in the series. Let's do it;
function findMissingItem(a,s){
return s(a[a.findIndex((f,i,a) => i ? f !== s(a[i-1]) : false)-1]);
}
var data1 = [1,2,3,5,6,7,8],
data2 = [1,4,9,16,36,49,64,81],
series1 = n => n+1,
series2 = n => Math.pow(Math.sqrt(n)+1,2);
res1 = findMissingItem(data1,series1),
res2 = findMissingItem(data2,series2);
console.log(res1);
console.log(res2);
Here's a simple solution using Array.reduce and the ES6 arrow function for brevity.
const array = [1, 2, 3, 5, 6, 7, 8];
const result = array.reduce((result, x) => x > result ? result : x + 1, 1)
console.log(result); // 4
With a little refactoring, we can start to make the solution more generic.
const sequence = [1, 2, 3, 5, 6, 7, 8];
const result = sequence.reduce(missingLinkReducer, sequence[0])
function missingLinkReducer(expected, actual) {
return expected === actual ? nextValue(expected) : expected;
}
function nextValue(value) {
return value + 1;
}
console.log(result);
Going a little bit further, we can make it so that different functions can be plugged in for calculating the next value.
const sequence = [1, 2, 3, 5, 6, 7, 8];
const result = sequence.reduce(createMissingLinkReducer(increment), sequence[0]);
console.log(result + ' is missing from ' + sequence);
const sequenceB = [1, 2, 4, 8, 16, 64, 128];
const resultB = sequenceB.reduce(createMissingLinkReducer(double), sequenceB[0]);
console.log(resultB + ' is missing from ' + sequenceB);
function createMissingLinkReducer(nextValue) {
return function missingLinkReducer(expected, actual) {
return expected === actual ? nextValue(expected) : expected;
}
}
function increment(value) {
return value + 1;
}
function double(value) {
return value * 2;
}
You can use every for this, below will work for any sequence interval you specify - it will return -1 if all elements are in sequence, or the element that doesn't fit:
var o = [1, 4, 7, 10, 11]
var seqInterval = 3;
function getMissing(arr, interval) {
var hit = -1;
var res = arr.every(function(e, i) {
hit = i === 0 ? hit : ((e - interval) === arr[i - 1] ? -1 : e);
return hit === -1;
});
return hit;
}
console.log(getMissing(o, seqInterval));
var o1 = [1,2,3,5,6,7,8];
var seqInterval1 = 1;
console.log(getMissing(o1, seqInterval1));

Categories

Resources