Reputation: 25
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?
Upvotes: 0
Views: 59
Reputation: 2115
Simply put each array item into the correspondent array index:
const groups = [];
input.forEach(
item => {
groups[item[0]-1] ??= [];
groups[item[0]-1].push(item);
}
);
That approach might result in empty array items, if there are missing numbers. Furthermore, it assumes the lowest number is 1. If you don't like those constraints, you may use an object instead:
const groupsObject = {};
input.forEach(
item => {
groupsObject[item[0]] ??= [];
groupsObject[item[0]].push(item);
}
);
const groups = Object.values(groupsObject);
Upvotes: 0
Reputation: 386604
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; }
Upvotes: 0
Reputation: 63524
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
Upvotes: 0
Reputation: 2236
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)
Upvotes: 0
Reputation: 132
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
Upvotes: 0
Reputation: 1372
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']]]
Upvotes: 2