Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using JavaScript Reduce to generate an object

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:[]});
like image 402
evsc Avatar asked Dec 03 '18 02:12

evsc


People also ask

Can we use reduce on objects in JavaScript?

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.

Can I use reduce on object?

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 .

Can you reduce an array into an object?

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.

Does reduce return a new object?

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.


Video Answer


2 Answers

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.

like image 86
Dacre Denny Avatar answered Oct 19 '22 16:10

Dacre Denny


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.

like image 25
Scott Sauyet Avatar answered Oct 19 '22 16:10

Scott Sauyet