-1

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)
  }
}
3
  • 3
    Why are there two 4's in your result? Commented Jul 5, 2022 at 14:07
  • @Ivar i didn't even notice, that is why i posted it here so you guys can help me out Commented Jul 5, 2022 at 14:52
  • no please @Yogi i think the second answer does Commented Jul 5, 2022 at 15:15

5 Answers 5

3

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 ]]
Sign up to request clarification or add additional context in comments.

Comments

2

We can write chunk(arr, size) using inductive reasoning -

  1. If arr.length is less than or equal to size, there are no more chunks to make. Return the singleton chunk of [ arr ]
  2. Otherwise (inductive) arr.length is greater than size, 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] ]

Comments

1

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.

2 Comments

Splice also has O(n) complexity right? So is this O(n^2) ?
Overall this algorithm is O(n), since the original array is never iterated over more than once. The for loop is iterated over nparts times and each call to slice is of cost O(n / nparts) roughly speaking. So nparts * O(n / nparts) = O(n) if you can forgive my abuse of the big-Oh notation to make this point.
1

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.

3 Comments

what if i want to split the array into 3 parts for any size of the array and not necessarily splitting it into the number of items it should contain
Do you mean getting 3 arrays with a random amount of the initial's array values? Like any of the following? One invocation: [ [1,2], [3], [4,5,6,7,8,9,10] ] Another invocation: [ []. [1,2,34,5,6,7,8], [9,10] ]
no please. don't worry someone answered it
0

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]

3 Comments

this doesn't work for const items = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19,20] like i want to dive the array into 3 parts it doesn't work
@MoroOwusuAfriyie updated code according.. now you can pass required number of element.. just take care of null and undefine, i did't handle edge cases :)
if i change the partitionSize to Math.ceil(items.length /4 ) it fails.. All i wanted was to be able to create sub arrays given the number of partitions i want . you can take a look at the second answer and try it out.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.