Home > Back-end >  Grouping arrays into further sub arrays
Grouping arrays into further sub arrays

Time:09-01

Say I have an array of arrays like so:

const input = [[1, 'aaa'], [1, 'bbb'], [2, 'ccc'], [2, 'ddd']]

I would like to arrange it so that they are futher sorted into groups of arrays, with the first element in each dictating how they are sorted. The result would look like this:

const output = [[[1, 'aaa'], [1, 'bbb']], [[2, 'ccc'], [2, 'ddd']]]

The first group would have all arrays where the first element is 1, the second group would all have 2 as the first element, and so forth.

The second solution to this question is probably the closest thing I can find: Grouping array group into separate sub array group

However, my modifications don't seem to work and I imagine I am misunderstand something about the functionality of .reduce(). What I've tried:

const input = [[1, 'aaa'], [1, 'bbb'], [2, 'ccc'], [2, 'ddd']];

const output = input.reduce(
  (r, c, i, a) => (
    c[0] != a[i - 1][0] ? r.push([c]) : r[r.length - 1].push(c), r
  ), []);

Am I heading in the right direction, or is there a more simple solution that lies elsewhere?

CodePudding user response:

So basically what i'm doing here (inside the .reduce()) is searching for a group that contains a value ([number, string]) which number (id) is equal to the number of the value i'm trying to add. If i find a group i push the new value (nv) inside that group, else i create a new group ([nv])

const input = [[1, 'aaa'], [1, 'bbb'], [2, 'ccc'], [2, 'ddd'], [4, 'aaa'], [5, 'aaa']]

const output = input.reduce((groups, nv) => {
    const group = groups.find(g => g.some(([id]) => id === nv[0]))
    
    if(!group) groups.push([nv])
    else group.push(nv)

    return groups
}, [])

// output: [[[1, 'aaa'], [1, 'bbb']], [[2, 'ccc'], [2, 'ddd']], [[4, 'aaa']], [[5, 'aaa']]]

CodePudding user response:

this algorithms might be readable. i use curIndex variable to track how to push the arrays

let curIndex = 0;
const output = input.reduce((prev: any, cur) => {
  // if prev is empty
  if (prev.length == 0) prev.push([cur]);
  // if the number equal the cur at current index
  else if (prev[curIndex][0][0] == cur[0]) prev[curIndex].push(cur);
  // create new array
  else {
    prev.push([cur]);
    curIndex  ;
  }

  return prev;
}, []);

I hope it will be helpful

CodePudding user response:

Assuming that it's possible for an index to be skipped, 1,2...4,5 I have used filter here to keep the reduce function as simple as possible.

const input = [[1, 'aaa'], [1, 'bbb'], [2, 'ccc'], [2, 'ddd'], [4, 'aaa'], [5, 'aaa']]

const output = input.reduce((acc, curr) => {
    const pos = curr[0] - 1
    if (!acc[pos]) acc[pos] = []
    return acc[pos].push(curr) && acc
}, []).filter(Boolean)

CodePudding user response:

Use an object to hold this information. The key is the first element of the nested array; the value is (initially) an empty array that you can push those nested arrays into.

Use a simple loop to achieve this, and finally return just the Object.values.

const input = [[1, 'aaa'], [1, 'bbb'], [2, 'ccc'], [2, 'ddd'], [1, 'ccc']];

function nest(arr) {
  const out = {};
  for (const [index, ...rest] of arr) {
    out[index] ??= [];
    out[index].push([ index, ...rest ]);
  }
  return Object.values(out);
}

console.log(JSON.stringify(nest(input)));

Additional documentation

CodePudding user response:

Just group with the help of an object.

const
    data = [[1, 'aaa'], [1, 'bbb'], [2, 'ccc'], [2, 'ddd']],
    result = Object.values(data.reduce((r, a) => {
        (r[a[0]] ??= []).push(a);
        return r;
    }, {}));

console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }

  • Related