Javascript - How to distribute items into a nested array, like dealing cards?

Viewed 264

This seems simple but I can't get it to work. What I'm trying to do is get items from an array and distribute those one by one into a nested array. Here is my code:

const numberOfSlots = 5;
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]

const nestedArray = Array(numberOfSlots).fill([])

_.forEach(numbers, (number, index) => {
  console.log('index', index);
  nestedArray[index % numberOfSlots].push(number)
  console.log('nested Array', nestedArray)

What I expected to see was something like this:

iteration 1: `[[1][][][][]`
iteration 2: `[[1][2][][][]`
iteration 3: `[[1][2][3][][]`
iteration 4: `[[1][2][3][4][]`
iteration 5: `[[1][2][3][4][5]`
iteration 6: `[[1, 6][2][3][4][5]`
iteration 7: `[[1, 6][2, 7][3][4][5]`
iteration 8: `[[1, 6][2, 7][3, 8][4][5]`

but what I get is this:

Why is this happening? As best I can tell it adds every item to every sub-array on each pass instead of only the array index I'm trying to push it to. How can I fix it?

3 Answers

Your issue is that each element in your top level array is a reference to the same array in memory, causing the behavior you're experiencing. One way to fix this is to use the map array method to make sure you're filling each element in the top level array with a unique object in memory.

const numberOfSlots = 5;

const numbers = [1, 2, 3, 4, 5, 6, 7, 8]

const nestedArray = Array(numberOfSlots)
  .fill(null)
  .map(() => new Array());

numbers.forEach((number, index) => {
 nestedArray[index % numberOfSlots].push(number)
})

console.log('nested Array', nestedArray)

You can group the numbers first and then fill the rest based on the index

numbers=[1, 2, 3, 4, 5, 6, 7, 8]
p=[]
res=[]
i=0
for(numb of numbers){
  if(!p[numb]) {
    if(res.length<5){
      res.push(p[numb]=[]) 
      p[numb].push(numb)         
    }
    else{
        res[i].push(numb) 
        i++
      }  
   }   
}
console.log(res)

If you don't want to use fill just to create an array to iterate over, there are other ways to achieve the same thing. E.g. you can use reduce:

let numberOfSlots = 5;
let numbers = [1, 2, 3, 4, 5, 6, 7, 8];

let nestedArray = numbers.reduce((acc, number, index) => {
  // Get the index of the subarray to put the number into
  let i = index % numberOfSlots;
  // If a subarray exists, push the number, otherwise create the subarray
  acc[i]? acc[i].push(number) : acc[i] = [number];
  // Return the accumulator
  return acc;
}, []);

console.log('nested Array: ' + JSON.stringify(nestedArray));

A side effect is that if there are fewer numbers than slots, the result will only have as many subarrays as there are numbers.

You can also use an old fashioned for loop:

let numberOfSlots = 5;
let numbers = [1, 2, 3];
let nestedArray = [];

for (let i=0, j; i < numberOfSlots || i < numbers.length; i++) {
  j = i % numberOfSlots;
  nestedArray[j] = nestedArray[j] || [];
  numbers[i]? nestedArray[j].push(numbers[i]) : null;
}

console.log('nested Array: ' + JSON.stringify(nestedArray));

Related