let's say i have an array [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and i want to split it into n parts let's say 3 part so the result is supposed to be [ 1, 2, 3, 4 ],[ 4, 5, 6, 7],[ 8, 9, 10 ] but the code i have right now is or O(n*m) which is bad. Is there an optimal way of doing this?
const items = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const n = 3
const result = [[], [], []]
const wordsPerLine = Math.ceil(items.length / 3)
for (let line = 0; line < n; line ) {
for (let i = 0; i < wordsPerLine; i ) {
const value = items[i line * wordsPerLine]
if (!value) continue //avoid adding "undefined" values
result[line].push(value)
}
}
CodePudding user response:
Assuming the result needs to be [[ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10 ]]
you could use Array.reduce:
const items = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
const parts = 3
const wordsPerLine = Math.ceil(items.length / parts)
const result = items.reduce((resultArray, item, index) => {
const arrayIndex = Math.floor(index / wordsPerLine)
if (!resultArray[arrayIndex]) {
resultArray[arrayIndex] = [] // start a new array
}
resultArray[arrayIndex].push(item)
return resultArray
}, [])
// result => [[ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10 ]]
CodePudding user response:
We can write chunk(arr, size)
using inductive reasoning -
- If
arr.length
is less than or equal tosize
, there are no more chunks to make. Return the singleton chunk of[ arr ]
- Otherwise (inductive)
arr.length
is greater thansize
, there is at least one chunk to make. Slice one chunk off the left of the array and prepend it to the result of the recursive sub-problem.
function chunk(arr, size) {
if (arr.length <= size)
return [ arr ] // 1
else
return [ arr.slice(0, size), ...chunk(arr.slice(size), size) ] // 2
}
const a =
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
const size =
Math.ceil(a.length / 3)
const result =
chunk(a, size)
console.log(
JSON.stringify(result)
)
[[0,1,2,3],[4,5,6,7],[8,9]]
Visualize the evaluation -
chunk([0,1,2,3,4,5,6,7,8,9], 4)
[ [0,1,2,3], ...chunk([4,5,6,7,8,9], 4) ]
[ [0,1,2,3], ...[ [4,5,6,7], ...chunk([8,9], 4) ] ]
[ [0,1,2,3], ...[ [4,5,6,7], ...[ [8,9] ] ] ]
[ [0,1,2,3], ...[ [4,5,6,7], [8,9] ] ]
[ [0,1,2,3], [4,5,6,7], [8,9] ]
CodePudding user response:
To split up the array as evenly as possible:
function split_array(a, nparts) {
const quot = Math.floor(a.length / nparts)
const rem = a.length % nparts
var parts = []
for (var i = 0; i < nparts; i) {
const begin = i * quot Math.min(rem, i)
const end = begin quot (i < rem)
parts.push(a.slice(begin, end))
}
return parts
}
var chunks = split_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3)
console.log(JSON.stringify(chunks))
Output:
[[1,2,3,4],[5,6,7],[8,9,10]]
The size of each part will never differ by more than 1.
CodePudding user response:
You could also use array.slice.
As the documentation reads, given the correct parameters, it will return a subset of your array, which you can then store into a new one.
For instance:
let n = 3;
let i = 0;
let resultArray = [];
let startArray = [1,2,3,4,5,6,7,8,9,10];
let arrayPortion = [];
const wordsPerLine = Math.ceil(startArray.length / n);
do {
arrayPortion = startArray.slice(n*i, n*(i 1));
resultArray.push(arrayPortion);
i ;
} while (arrayPortion.length==n && i*n<startArray.length); // Your end conditions.
This should work for any n
.
CodePudding user response:
With O(n)
const items = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19,20]
const partitionSize = Math.ceil(items.length / 3)
const result = [[], [], []]
let resultIndex = 0, subArrayIndex = 0;
for (let line = 0; line < items.length; line ) {
result[resultIndex].push(items[line])
subArrayIndex ;
if(subArrayIndex == partitionSize) {
resultIndex ;
subArrayIndex = 0;
}
}
Result:
0: (7) [1, 2, 3, 4, 5, 6, 7]
1: (7) [8, 9, 10, 11, 12, 13, 14]
2: (6) [15, 16, 17, 18, 19, 20]