Home > OS >  How to group nested array in Javascript?
How to group nested array in Javascript?

Time:09-19

Does anyone know how to group nested arrays in Javascript like this? (can be vanilla or lodash method) (I work on Reactjs)

from

[[ 5, '103' ], [ 3, '104' ], [ 1, '105' ], [ 1, '106' ], [ 2, '107' ], [ 1, '108' ], [ 5, '109' ], [ 3, '110' ]]

to

{5: ['103','109'], 3: ['104','110'], 2: ['107'], 1: ['105','106','108']}

or

[[5, ['103','109']], [3, ['104','110']], [2, ['107']], [1, ['105','106','108']]]

Thank you

CodePudding user response:

I'm sure we can find a couple of lodahs functions that will solve the problem together. But I think the easiest way to go about is a custom Array reducer.

const array = [[ 5, '103' ], [ 3, '104' ], [ 1, '105' ], [ 1, '106' ], [ 2, '107' ], [ 1, '108' ], [ 5, '109' ], [ 3, '110' ]];

const result = array.reduce((acc, [key, value]) => ({
    ...acc,
    [key]: [
        ...acc[key] || [],
        value,
    ]
}), {});

console.log(result)

CodePudding user response:

Use _.groupBy() the _.head() (the 1st element of the array), and then map the values and extract the last parameter from each of the sub-arrays in the group.

Note: since we're grouping the array into an object, and the keys are integers, the order of the keys would be numeric ascending.

const { mapValues, groupBy, head, map, last } = _;

const array = [[ 5, '103' ], [ 3, '104' ], [ 1, '105' ], [ 1, '106' ], [ 2, '107' ], [ 1, '108' ], [ 5, '109' ], [ 3, '110' ]];

const result = mapValues(
  groupBy(array, head),
  arr => map(arr, last)
);

console.log(result);
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG ljU96qKRCWh quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Without lodash you can reduce the array to a Map, and then convert the Map's to an array using Array.from() or to an object using Object.fromEntries().

Note: A Map preserves the order of insertion, even for integer keys, and converting the Map to an array of arrays would also maintain the original order.

const array = [[ 5, '103' ], [ 3, '104' ], [ 1, '105' ], [ 1, '106' ], [ 2, '107' ], [ 1, '108' ], [ 5, '109' ], [ 3, '110' ]];

const map = array.reduce((acc, [key, val]) => {
  if(!acc.has(key)) acc.set(key, []);
  
  acc.get(key).push(val);
  
  return acc;
}, new Map());

console.log(Array.from(map)); // convert the Map to an array

console.log(Object.fromEntries(map)) // convert the Map to an object
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG ljU96qKRCWh quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

CodePudding user response:

If you need to group like objects, try this

function group(inarr){
  let outarr = inarr.reduce((r,a)=>{
    if(!r[a[0]]) r[a[0]] = [];
    r[a[0]].push(a[1])
    return r;
  }, {});
  console.log(outarr)
}

CodePudding user response:

It can be done in vanillaJS by looping the array in forEach loop and for each cycle add the value to the object.

const toBeGrouped = [[ 5, '103' ], [ 3, '104' ], [ 1, '105' ], [ 1, '106' ], [ 2, '107' ], [ 1, '108' ], [ 5, '109' ], [ 3, '110' ]]

let grouped = {};
let k;
let value;
toBeGrouped.forEach((item) => {
  k = item[0];
  value = item[1];
  //check if the object key exists, then check is an array, then check if the current value is in the 
  if (grouped[k] && Array.isArray(grouped[k]) &&  !grouped[k].includes(value)) {
    grouped[k].push(value);
  } else {
    grouped[k] = [value];
  }
});
console.log(grouped)

  • Related