Search code examples
javascriptreactjslodash

How to group nested array in Javascript?


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


Solution

  • 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>