2

I have array like this:

[{i: 0, abc: true}, {i: 1, abc: true}, {i: 2, abc: true}, {i: 3, abc: true}, {i: 4, abc: true}, {i: 5, abc: true}, {i: 6, abc: true}, {i: 7, abc: true}, {i: 8, abc: true}, {i: 9, abc: true}, {i: 10, abc: true}, {i: 11, abc: true}, ]

I need to chunk it too have on output something like this:

[[{i: 0, abc: true}, {i: 1, abc: true}, {i: 2, abc: true}], [{i: 3, abc: true}, {i: 4, abc: true}, {i: 5, abc: true}], [{i: 5, abc: true}, {i: 6, abc: true}, {i: 7, abc: true}], [{i: 7, abc: true}, {i: 8, abc: true}, {i: 9, abc: true}], [{i: 9, abc: true}, {i: 10, abc: true}, {i: 11, abc: true}] ]

Last object in sub array is same as first object in next sub array.

Currently I write something like this :

const chunk = (arr, size) => Array.from( { length: Math.ceil(arr.length / size) }, (v, i) =>
arr.slice(i * size, i * size + size));

but it's only chunking by a specific number of elements. I can also achieve my goal by strange nested loops.. but maybe somebody knows better.. simpler way?

Nilay Singh
  • 2,201
  • 6
  • 31
  • 61
Kishieel
  • 1,811
  • 2
  • 10
  • 19

2 Answers2

1

You can remove 1 from the slice start and end if the current chunk index (i) is not 0. However, since we're moving the index backwards by 1, we might have more chunks. We need to compare the number of total chunks with the decremented index, and without, and add to the number of pages accordingly.

const chunkMinus1 = (arr, size) => {
  const chunks = Math.ceil(arr.length / size)
  const maxItems = chunks * (size - 1) + 1
  const length = chunks + Math.ceil(Math.max(arr.length - maxItems, 0) / size)
  
  return Array.from(
    { length }, 
    (v, i) => arr.slice(i * size - (i ? 1 : 0), i * size + size - (i ? 1 : 0))
  )
};

const arr = [{i: 0, abc: true}, {i: 1, abc: true}, {i: 2, abc: true}, {i: 3, abc: true}, {i: 4, abc: true}, {i: 5, abc: true}, {i: 6, abc: true}, {i: 7, abc: true}, {i: 8, abc: true}, {i: 9, abc: true}, {i: 10, abc: true}, {i: 11, abc: true}]

const result = chunkMinus1(arr, 6)

console.log(result)
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • 1
    Thanks. Your answer is not exactly what I want, but I improved it and now I have exactly what I needed.. const chunk = (arr, size) => Array.from( { length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size + 1 ) ); – Kishieel Apr 30 '20 at 21:20
  • 1
    @tomcio61 - I've updated the answer to account for missing items, when the number of chunks doesn't cover all items because of the reduction in the index. – Ori Drori Apr 30 '20 at 21:20
1

Here is a very simple way how to do it.

Introduce a new array every nth element (for your case every third) by using the modulo, find that nth element and add the elements to the last sub-array.

Fiddle proof: https://jsfiddle.net/2pzcLv9k/

   const result = input.reduce((acc, x, i) => {
   if (i % 3 === 0) {
     acc.push([x])
   } else {
     acc[acc.length - 1].push(x)
   }
   return acc;
 }, [])
EugenSunic
  • 13,162
  • 13
  • 64
  • 86