I have an array of arrays of different sizes. The goal is to generate "rows" where each row can contain a max of 12 elements. For example:
Input data can be something like this:
const groups = [[1,2,3,4],[1,2,3,4,5,6], [1,2,3,4,5,6,7,8,9,10,11,12], [1,2,3,4,5,6,7], [1,2,3],[1,2,3]]
groups[0].length groups[1].length = 10 -> row0
groups[2].length = 12 -> row1
groups[3].length groups[4].length = 10 -> row3
groups[5].length = 3 -> row4
Output for such array should be:
const rows = [[[1,2,3,4], [1,2,3,4,5,6]], [[1,2,3,4,5,6,7,8,9,10,11,12]], [[1,2,3,4,5,6,7], [1,2,3]], [[1,2,3]]]
I was thinking of a recursive function for this but couldn't figure out how to solve it.
CodePudding user response:
You can use Array#reduce()
to do this.
The code first checks if the current last element (last "row") has more than 12 numbers in it if you add the next group:
(acc[acc.length - 1].flat().length cv.length) <= 12
if it will be less than 12, the elements will get pushed into the "row":
acc[acc.length - 1].push(cv)
and if not, a new "row" will be added to the outer array:
acc.push([cv])
const groups = [[1, 2, 3, 4],[1, 2, 3, 4, 5, 6],[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],[1, 2, 3, 4, 5, 6, 7],[1, 2, 3],[1, 2, 3]];
const rows = groups.reduce((acc, cv) => {
(acc[acc.length - 1].flat().length cv.length) <= 12 ?
acc[acc.length - 1].push(cv) :
acc.push([cv])
return acc
}, [[]]);
console.log(JSON.stringify(rows))
CodePudding user response:
Here's one way to solve it recursively:
const regroup = (max, [g, ...gs], filled = [], curr = [], cc = 0) =>
g == undefined
? filled .concat ([curr])
: g .length cc <= max
? regroup (max, gs, filled, curr .concat ([g]), cc g.length)
: regroup (max, gs, filled .concat ([curr]), [g], g .length)
const groups = [[1, 2, 3, 4], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
[1, 2, 3, 4, 5, 6, 7], [1, 2, 3], [1, 2, 3]]
console .log (regroup (12, groups))
.as-console-wrapper {max-height: 100% !important; top: 0}
We pass the maximum size and the list of items, and then we default three parameters:
filled
will track the output rows we've filled; it starts with an empty arraycurr
stores the row we're working on; it also starts with an empty arraycc
stores the count of all elements in the current row; it starts with zero
On each recursive call, we have one of three possibilities:
- There are no more arrays to process, and we return all the filled rows with the current row appended.
- The next array is small enough to fit in the current row, and we update the current to include it, and the current count to accommodate it.
- The next array is too large, and we add the existing current row to the filled ones, and start a new current row with this array, setting the count appropriately.