Home > Software engineering >  How to loop and push on the accumulator of a reduce function?
How to loop and push on the accumulator of a reduce function?

Time:04-21

I'm trying to reduce an array, and transform it in multiple array.

  const array = [
    { a: 1, b: 6 },
    { a: 1, b: 5 },
    { a: 1, b: 6 },
    { a: 1, b: 4 },
    { a: 1, b: 5 }
  ];

  var newArray = array.reduce(
    (memo, curr) => {
      memo.forEach((item, key) => {
        const found = item.filter((el) => el.a === curr.a && el.b === curr.b);
        if (found.length > 0) return memo[key].push(curr);
        else return memo.push([curr]);
      });

      return memo;
    },
    [[]]
  );

The needed result I try to get is

 [
    [
      { a: 1, b: 5 },
      { a: 1, b: 5 }
    ],
    [
      { a: 1, b: 6 },
      { a: 1, b: 6 },
    ],
    [
      { a: 1, b: 4 },
    ]
 ];

But as you can see if you try, because I push on the memo, the loop continue to fire. And the result contain hundreds arrays.

How I'm supposed to do to limit this loop and get the right result ?

Thanks a lot in advance :)

CodePudding user response:

You could use Map to group the element by the key of {a, b}, and then get the values of the group

const array = [
  { a: 1, b: 6 },
  { a: 1, b: 5 },
  { a: 1, b: 6 },
  { a: 1, b: 4 },
  { a: 1, b: 5 },
];

var newArray = Array.from(
  array
    .reduce((map, curr) => {
      const key = JSON.stringify({ a: curr.a, b: curr.b });

      if (!map.has(key)) {
        map.set(key, []);
      }

      map.get(key).push(curr);

      return map;
    }, new Map())
    .values()
);

console.log(newArray);

CodePudding user response:

Look at your code. You have a triple nested loop, which is insane and definitely not needed to achieve this. Why not use a map?

Here is a function that will do what you want to do with any array of objects given.

const array = [
    { a: 1, b: 6 },
    { a: 1, b: 5 },
    { a: 1, b: 6 },
    { a: 1, b: 4 },
    { a: 1, b: 5 },
];

const separate = (arr) => {
    const reduced = arr.reduce((acc, curr) => {
        const path = JSON.stringify(curr);

        if (!acc[path]) acc[path] = [];

        acc[path].push(curr);

        return acc;
    }, {});

    return Object.values(reduced);
};

console.log(separate(array));

CodePudding user response:

If you push inside for loop it will going to push for every reduce function iteration also.

you can achieve by adding some local variables like here

const array = [
    { a: 1, b: 6 },
    { a: 1, b: 5 },
    { a: 1, b: 6 },
    { a: 1, b: 4 },
    { a: 1, b: 5 }
  ];
  
  // shift changes the orginal array
    // it will remove and return firstElement
  var firstElement = array.shift(1);


  var newArray = array.reduce(
    (memo, curr) => {
    let isFound = false;
    let index = 0;
      memo.forEach((item, key) => {
        const found = item.filter((el) => el.a === curr.a && el.b === curr.b);
        if(found.length > 0){
             index = key;
           isFound = true;
           return;
        }
       
      });
      if(isFound) {
        memo[index].push(curr);
      } else {
         memo.push([curr]);
      }
      return memo;
    },
    [[firstElement]]
  );
  
  console.log(newArray);

  • Related