Split Array Up into N-Groups of M Size

Split array up into n-groups of m size?

Use Enumerable#each_slice.

a.each_slice(3).to_a

Or, to iterate (and not bother with keeping the array):

a.each_slice(3) do |x,y,z|
p [x,y,z]
end

Splitting an array into groups

You modify size inside the loop. This basically doubles the size at every step. The fact that your example only has two sub-arrays hides this problem. Try larger arrays to see the problem in the result.

To fix this, declare j outside of the loop. Add the size to j after slicing.

Edit: Code, as requested

function chunkArrayInGroups(arr, size) {
var result = [];
var j = 0;
for (var i = 0; i < Math.ceil(arr.length / size); i++) {
result[i] = arr.slice(j, j + size);
j = j + size;
}
return result;
}

Or, slightly simplified:

function chunkArrayInGroups(arr, size) {
let result = [];
let pos = 0;
while (pos < arr.length) {
result.push(arr.slice(pos, pos + size));
pos += size;
}
return result;
}

How to split a long array into smaller arrays, with JavaScript

Don't use jquery...use plain javascript

var a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];

var b = a.splice(0,10);

//a is now [11,12,13,14,15];
//b is now [1,2,3,4,5,6,7,8,9,10];

You could loop this to get the behavior you want.

var a = YOUR_ARRAY;
while(a.length) {
console.log(a.splice(0,10));
}

This would give you 10 elements at a time...if you have say 15 elements, you would get 1-10, the 11-15 as you wanted.

Split array into chunks

The array.slice() method can extract a slice from the beginning, middle, or end of an array for whatever purposes you require, without changing the original array.

const chunkSize = 10;
for (let i = 0; i < array.length; i += chunkSize) {
const chunk = array.slice(i, i + chunkSize);
// do whatever
}

The last chunk may be smaller than chunkSize. For example when given an array of 12 elements the first chunk will have 10 elements, the second chunk only has 2.

Note that a chunkSize of 0 will cause an infinite loop.

How to split an array into even length chunks?

With this solution you get evenly split array items until the last item which incorporates any left over items (collection of items that's length is less than the chunk size.)

const a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]const chunk = 4
const chunk_array = (a, c) => { let arr = [] a.forEach((_, i) => { if (i%chunk === 0) arr.push(a.slice(i, i+chunk)) }) const [left_overs] = arr.filter(a => a.length < chunk) arr = arr.filter(a => a.length >= chunk) arr[arr.length-1] = [...arr[arr.length-1], ...left_overs] return arr}
console.log( chunk_array(a, chunk))

Splitting array into groups using typescript/javascript

Use Array.reduce()

You can run a .reduce() method on your products array, like so:

var products = [   { 'id': 1, name: 'test' },   { 'id': 2, name: 'test' },   { 'id': 3, name: 'test' },   { 'id': 4, name: 'test' },   { 'id': 5, name: 'test'  },   { 'id': 6, name: 'test' }]
var numberOfObjects = 4 // <-- decides number of objects in each group
var groupedProducts = products.reduce((acc, elem, index) => { var rowNum = Math.floor(index/numberOfObjects) + 1 acc[`row${rowNum}`] = acc[`row${rowNum}`] || [] acc[`row${rowNum}`].push(elem) return acc}, {})
console.log(groupedProducts)

Split an array into smaller chunks of arrays with the length provided by size. Need explanation for solution with modulo

Instead of using your (definitely more efficient, and also clearer) approach of taking consecutive slices, this takes the array item by item, storing the next group to be added in a temporary array. The test is basically asking (with a weird negative test) "Is this index not the last one in the group?" If that condition is true, and we're not on the last one for the current group, we simply add to the temporary group. If it's false, and we are on the last one, we add to the temporary group, add the temporary group to our output and create a new temporary group.

With a little refactoring, we can make this cleaner, perhaps something like this:

function chunkArrayInGroups(arr, size) {
const result = []
let temp = []

for (let a = 0; a < arr .length; a ++) {
temp .push (arr [a])
if (a % size === size - 1) {
result .push (temp)
temp = []
}
}

if (temp .length > 0) result .push (temp)

return result
}

But this holds no advantages over your approach, and is definitely less efficient. So I wouldn't consider it.

Here's an alternative that is to my mind cleaner, but also less efficient than yours:

const chunk = (xs, n) => xs .length <= n 
? [[...xs]]
: [xs .slice (0, n)] .concat (chunk (xs .slice (n), n))

This one grabs the first group by slicing it from the beginning of the array, and concatenates the results of recursively calling itself with the remainder of the array. The recursion ends when there are at most n elements remaining, and then we return an array containing only a copy of our input array ([[...x]]). We make the copy because all the other results are copies and not references, and it's better to be consistent.

This is similar to your approach in terms of number of slices and tests, but because of the recursive nature, it will fail for very large arrays and the repeated calls will make it somewhat less efficient. I'm often willing to take that tradeoff for cleaner code, myself, but YMMV.

Split Array of items into N Arrays

I'm not 100% sure how this should work on different sized arrays with different group counts, but this works for your 12 digit example:

function chunkArray(arr, chunkCount) {  const chunks = [];  while(arr.length) {    const chunkSize = Math.ceil(arr.length / chunkCount--);    const chunk = arr.slice(0, chunkSize);    chunks.push(chunk);    arr = arr.slice(chunkSize);  }  return chunks;}

var arr = [1,2,3,4,5,6,7,8,9,10,11,12];console.log( chunkArray(arr, 5) )

Splitting String Arrays into Groups

I would suggest changing your code to calculate the number of groups you need to this:

int groups = (count / groupSize);
bool hasPartialGroup = count % groupSize != 0;
if (hasPartialGroup)
{
++groups;
}

The result of the first line will be integer division, so 15 / 6 will result in 2. We then see if there is a remainder using the remainder operator (%): count % groupSize. If its result isn't 0, then there is a remainder, and we have a partial group, so we have to account for that.

So for groups = 15 and groupSize = 6, we'll get count = 3. For groups = 12 and groupSize = 6, we'll get count = 2, etc.

Fixing your code to use this, it might look like:

string[] tags = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"};

int count = tags.Length;
const int groupSize = 6;
int groups = (count / groupSize);
bool hasPartialGroup = count % groupSize != 0;
if (hasPartialGroup)
{
++groups;
}

for (int i = 0; i < groups; i++)
{
// you can't copy beyond the end of the array so we have to choose between the remaining ungrouped items and the group size
int currentGroupSize = Math.Min(tags.Length - i*groupSize, groupSize);
// I'm assuming for a partial group you only want this to be as big as the number of items.
// If you want it to always be 6 then change new string[currentGroupSize] to new string[groupSize] and you should be OK.
string[] groupArrays = new string[currentGroupSize];
Array.Copy(tags, i * groupSize, groupArrays, 0, currentGroupSize);
Console.WriteLine(string.Join(",", groupArrays));
}

Try it online // Example with fixed group size


Alternatively, you could create a batching helper method:

private static IEnumerable<T[]> BatchItems<T>(IEnumerable<T> source, int batchSize)
{
var collection = new List<T>(batchSize);
foreach (var item in source)
{
collection.Add(item);
if (collection.Count == batchSize)
{
yield return collection.ToArray();
collection.Clear();
}
}

if (collection.Count > 0)
{
yield return collection.ToArray();
}
}

This will collect batchSize number items together and then return one group at a time. You can read about how this works with yield return here.

Usage:

string[] tags = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"};
List<string[]> batchedTags = BatchItems(tags, 6).ToList();

This will result in 3 string arrays, containing 1,2,3,4,5,6, 7,8,9,10,11,12, and 13,14,15.

You could also make this into an extension method.

Try it online



Related Topics



Leave a reply



Submit