How to batch group of array elements in reference to another array of group size?

142 Views Asked by At

How to batch group of array elements in reference to another array of group size ? I tried below code.

Code:

var group_size = [1, 3, 5];
var elements = ['a','b','c','d','e','f','g','h','i','j','k','l'];
        
var output = [];
    for (var i=0; i < group_size.length; i++) {
    output.push(elements.slice(i, group_size[i]))
}
console.log(output);

Output:

[["a"], ["b", "c"], ["c", "d", "e"]]

But expected output:

[['a'], ['b','c','d'],['e','f','g','h','i'],['j','k','l']]

If there are moe elements, then those elements to be grouped by max group_size element.

Example :

Input = ['a','b','c']
Output = [['a'], ['b','c']]

Input = ['a','b','c','d','e']
Output = [['a'], ['b','c','d'], ['e']]

Input = ['a','b','c','d','e','f','g','h','i','j','k','l']
Output = [['a'], ['b','c','d'],['e','f','g','h','i'],['j','k','l']]

Input = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p']
Output = [['a'], ['b','c','d'],['e','f','g','h','i'],['j','k','l','m','n'], ['o','p']]

I tried above code but that's limiting. How can I do it in ecma5 (js) ?

5

There are 5 best solutions below

3
blakkwater On BEST ANSWER

What do you need for the solution:

  1. Keep a track of the largest group length.
  2. Keep a track of the offset at which the next group should start.
  3. Slice groups while they are within the range of the source array.
  4. If the array is larger than the sum of all groups, continue slicing chunks equal to the length of the largest group.

function splitIntoGroups (array, groups) {
    let output = [];
    let maxLength = 1;
    for (var i=0, offset=0; i < groups.length && offset < array.length; i++) {
        output.push(array.slice(offset, offset + groups[i]));
        offset += groups[i];
        maxLength = Math.max(maxLength, groups[i]);
    }
    while (offset < array.length) {
        output.push(array.slice(offset, offset + maxLength));
        offset += maxLength;
    }
    return output;
}

let elements = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'];
let groups = [1, 3, 5, 5, 5, 1000];

// when sum of all groups exceeds the source array,
// they are truncated to match the array
console.log(splitIntoGroups(elements.slice(0, 3), groups));
console.log(splitIntoGroups(elements.slice(0, 5), groups));
console.log(splitIntoGroups(elements.slice(0, 12), groups));
console.log(splitIntoGroups(elements, groups));

// when sum of all groups doesn't exceed the source array,
// the largest group is repeated until the end of the array
console.log(splitIntoGroups(elements, [1, 3, 5]));

0
Artur Minin On

Here is the code that will give you the desired result:

const groupSize = [1, 3, 5];
const elements = ['a','b','c','d','e','f','g','h','i','j','k','l'];
const maxGroupSize = Math.max(...groupSize);

let groupIndex = 0;
let startElementIndex = 0;
let output = [];
while (startElementIndex <= elements.length) {
  const currentGroupSize = groupSize[groupIndex] ?? maxGroupSize;
  output.push(elements.slice(startElementIndex, startElementIndex + currentGroupSize));

  startElementIndex += currentGroupSize;
  groupIndex++;
}

Steps:

  1. Determine the largest group maxGroupSize
  2. Iterate until there are elements left in the elements array
  3. On each iteration push the number of elements that corresponds to the current group size, otherwise use the value from maxGroupSize as a group size
  4. Update indexes for the start index(startElementIndex) and the group index(groupIndex)
0
Gustavo Shigueo On

This code worked with all your provided inputs and should be compatible with es5

function groupArray(arr, sizes) {
  if (sizes.length == 0) {
    throw new Error('Sizes array must not be empty')
  }

  var maxSize = Math.max.apply(null, sizes)

  var index = 0
  var output = []
  
  for (var size of sizes) {
    if (index >= arr.length) break

    output.push(arr.slice(index, index + size))
    index += size
  }

  for (var i = index; i < arr.length; i += maxSize) {
    output.push(arr.slice(i, i + maxSize))
  }

  return output
}
4
WhoLostEvee On

Alright here is the best solution, you were right (almost), instead of using slice you should have used splice to get the right response, you can read about it here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

The code below is exactly the same as yours but just with the correction. Hope this helps.

var group_size = [1, 3, 5];
var elements = ['a','b','c','d','e','f','g','h','i','j','k','l'];
    
var output = [];
    for (var i=0; i < group_size.length; i++) {
        output.push(elements.splice(i, group_size[i]))
    }

console.log(output);
0
Siva K V On

Use while loop and using max group size when groups out of bounds

var group_size = [1, 3, 5];
var elements = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l",'m','n','o','p'];

const max_size = Math.max(...group_size);
const output = [];
let last = 0;
let i = 0;

while (last < elements.length) {
  output.push(elements.slice(last, last += (group_size[i] ?? max_size)));
  i++;
}
console.log(output);