I have an array of numbers [22, 44, 12, 9, 4, 23, 1, 11, 10, 5, 2, 123]
, I need to use reduce to create an object that looks like this:
{
numbersLessThanTen: [...],
numbersGreaterThanTen: [...]
}
I have the solution, which is the below:
const listOfNumbers = [22, 44, 12, 9, 4, 23, 1, 11, 10, 5, 2, 123];
const groupedBySize = listOfNumbers.reduce((total, next) => {
const less = total.numbersLessThanTen || [];
const more = total.numbersGreaterThanTen || [];
next > 10 ? total.numbersGreaterThanTen = [].concat(more, next) : total.numbersLessThanTen = [].concat(less, next);
return total;
}, {});
My question is, why does the following not work? It just returns the initial value. It works when I use .push() instead of .concat() but I really want to understand why this way does not work. Thank you!
const groupedBySize = listOfNumbers.reduce((total, next) => {
// const less = total.numbersLessThanTen || [];
// const more = total.numbersGreaterThanTen || [];
next > 10 ? total.numbersGreaterThanTen.concat(next) : total.numbersLessThanTen.concat(next);
return total;
}, {numbersGreaterThanTen: [], numbersLessThanTen:[]});
The array reduce in JavaScript is a predefined method used to reduce an array to a single value by passing a callback function on each element of the array. It accepts a function executed on all the items of the specified array in the left-to-right sequence. The returned single value is stored in the accumulator.
But did you know you can reduce them to objects as well? First, a quick overview of how reduce works. The reduce method receives two arguments: a function and an initial value. The function will run run for every value in the array, and receives two arguments as well: the accumulator, or acc , and the current value .
To convert an array into an object we will create a function and give it 2 properties, an array and a key. const convertArrayToObject = (array, key) => {}; We will then reduce the array, and create a unique property for each item based on the key we have passed in.
reduce() returns the value that is returned from the callback function on the final iteration of the array. reduce() is a central concept in functional programming, where it's not possible to mutate any value, so in order to accumulate all values in an array, one must return a new accumulator value on every iteration.
The reason your code doesn't work is becase concat()
returns the result of concatentation as a new array. When your reduce function runs, the concatentation work is done, but the result of that concatentation isn't assigned to anything (ie a field in total
). This is the reason the output result appears is identical to the input - the arrays in total
never actually get updated. The following is from MDN
The concat method creates a new array consisting of the elements in the object on which it is called.
The push()
method on the other hand actually mutates/updates the array that it's called on, adding what ever data you pass directly to that array instance. This means when push()
is called per iteration, the arrays in total
are updated directly which is why this approach works:
The push method appends values to an array.
Others explained why that approach didn't work, and gave reasonable answers, continuing the mutation.
Here is an approach that doesn't mutate any data:
const listOfNumbers = [22, 44, 12, 9, 4, 23, 1, 11, 10, 5, 2, 123];
const groupedBySize = nbr => nbr.reduce
( ({ gt10, lte10 }, next) => next > 10
? { gt10: gt10 .concat(next), lte10 }
: { gt10, lte10: lte10 .concat(next) }
, { gt10: [], lte10: [] }
)
console.log(groupedBySize(listOfNumbers))
I also shorted the property names. Obviously you could re-lengthen them. But do note that "numbersLessThanTen"
is a bit misleading, as it includes 10
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With