Reputation: 97
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:[]});
Upvotes: 6
Views: 1345
Reputation: 18515
Array.concat does not mutate the array on which it is called. You are assuming that and not assigning the result to anything ... as per docs:
This method does not change the existing arrays, but instead returns a new array
So to get what you want with your code you could do something like this:
const listOfNumbers = [22, 44, 12, 9, 4, 23, 1, 11, 10, 5, 2, 123];
const groupedBySize = listOfNumbers.reduce((total, next) => {
let key = next > 10 ? 'numbersGreaterThanTen' : 'numbersLessThanTen'
total[key] = total[key].concat([next]); // <-- assign the result
return total;
}, {numbersGreaterThanTen: [], numbersLessThanTen: []});
console.log(groupedBySize)
Alternatively you could just do this:
const listOfNumbers = [22, 44, 12, 9, 4, 23, 1, 11, 10, 5, 2, 123];
const groupedBySize = listOfNumbers.reduce((ttl, nxt) =>
(ttl[nxt > 10 ? 'numbersGreaterThanTen' : 'numbersLessThanTen'].push(nxt), ttl),
{numbersGreaterThanTen: [], numbersLessThanTen:[]});
console.log(groupedBySize)
Which does the same thing but uses Array.push
which mutates
the array on which it is called by inserting the item.
Upvotes: 0
Reputation: 92440
You can decide which array with the ternary and then push()
instead of concat()
:
let n = [22, 44, 12, 9, 4, 23, 1, 11, 10, 5, 2, 123]
let obj = n.reduce((obj, n) => {
(n < 10
? obj.numbersLessThanTen
: obj.numbersGreaterThanTen
).push(n)
return obj
}, {numbersLessThanTen: [], numbersGreaterThanTen:[]})
console.log(obj)
Upvotes: 1
Reputation: 50787
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
.
Upvotes: 1
Reputation: 30360
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.
Upvotes: 1