skip to Main Content

I have data that I need to gather in a very specific way. Right now, the data comes in the form of N arrays (of arrays) all of M length. M will be the same for all arrays for a given invocation.

So the following example has N=2 and M=3. The length of the final nested arrays is variable and can be 0 or more (but it will be an empty array of length zero)

[
  [
    ['a', 'b'], ['c'], ['d']
  ],
  [
    ['e'], ['f', 'g'], ['h']
  ]
]

What I need is

[['a', 'b', 'e'], ['c', 'f', 'g'], ['d', 'h']]

I can get a working answer but it’s gross, and I was hoping someone had a more elegant approach.

Here’s the (sort of) working solution:

const gatheredData = [[]];
const final = _.forEach(startData, (array, arrayIndex) => {
  // This is intended to handle the basecase creation of empty arrays
  if (_.size(gatheredData) < arrayIndex) {
    gatheredData.concat([]);
  }
  gatheredData[arrayIndex].concat(array);
});

That also seems to error out in edge cases I haven’t quite drilled down into yet.

5

Answers


  1. You can use mergeWith

    const startData = [
      [ ['a', 'b'], ['c'], ['d'] ],
      [ ['e'], ['f', 'g'], ['h'] ]
    ];
    
    const gatheredData = _.mergeWith(
      [[]], 
      ...startData, 
      (source1 = [], source2 = []) => source1.concat(source2)
      );
    
    console.log( gatheredData );
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
    Login or Signup to reply.
  2. One option without lodash would be to first map the nested array within your array, where for each inner (leaf) array (eg: ['a', 'b']), you concatenate with an array containing all inner elements at the same index (that you can obtain with mapping all other arrays), eg:

    const arr = [
      [['a', 'b'], ['c'], ['d']],
      [['e'], ['f', 'g'], ['h']]
    ];
    
    const zipArrs = ([first = [], ...rest]) => first.map(
      (arr, i) => arr.concat(...rest.map(other => other[i]))
    );
    
    console.log(zipArrs(arr));
    Login or Signup to reply.
  3. This seems to do the trick:

    // Assuming your initial arr is called arrs
    const result = [];
    
    arrs.forEach(arr => {
        arr.forEach((subArr, index) => {
            if (!result[index]) {
                result[index] = [];
            }
            
            result[index].push(...subArr);
        });
    });
    
    Login or Signup to reply.
  4. You can use map and flatMap like this:

    const data = [
      [
        ['a', 'b'], ['c'], ['d']
      ],
      [
        ['e'], ['f', 'g'], ['h']
      ]
    ];
    
    const gatheredData = data[0].map((_, i) => data.flatMap(arr => arr[i]));
    
    console.log(gatheredData);
    Login or Signup to reply.
  5. with lodash you can use _.unzipWith(), and pass _.concat() as the iteratee:

    const arr = [[['a', 'b'], ['c'], ['d']],[['e'], ['f', 'g'], ['h']]];
    
    const result = _.unzipWith(arr, _.concat);
    
    console.log(result);
    <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>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search