Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Splitting a vector into groups of a predefined size

I'm looking for a way to split an input vector into groups of a predefined size, with the last group being smaller if there is a remainder. I prefer the output as a cell, but I don't mind if it's any other class as long as it provides access to the subgroups using subsequent indexing.

Below are examples of the expected behavior:

% Even split
v = 1:6;
grpSz = 2;
% OUT: {[1,2], [3,4], [5,6]}

% Remainder
v = 1:5;
grpSz = 3;
% OUT: {[1,2,3], [4,5]}

% Single group
v = 1:5;
grpSz = 6;
% OUT: {[1,2,3,4,5]}

Below are a couple of useful quantities:

  • Number of groups in the output: nG = ceil(numel(v)/grpSz)
  • Number of elements in the last group: r = mod(numel(v), grpSz)

At the moment I'm using mat2cell:

function out = evenSplitter(v, grpSz)
nV = numel(v);
nG = ceil(nV/grpSz);
r = mod(nV, grpSz);
out = mat2cell(v, 1, [repmat(grpSz, 1, nG-1), ~r*grpSz+r]);

...which works, but looks a bit clunky. Would anybody suggest a more elegant solution?

like image 341
Dev-iL Avatar asked Dec 30 '22 18:12

Dev-iL


1 Answers

One solution using splitapply:

v     = 1:5;                                           % input array
grpSz = 2;                                             % maximal group size
out   = splitapply(@(x){x},v,ceil((1:numel(v))/grpSz)) % split v

This method works for all the given examples.

splitapply split data into groups and apply function. The anonymous function @(x){x} simply put each element of a group into a cell. And ceil((1:numel(v))/grpSz) create an array that indicate which elements are associated with which groups.

For example, if v = 1:5 and grpSz = 2, ceil((1:numel(v))/grpSz) produce the following array [1 1 2 2 3].

like image 145
obchardon Avatar answered Jan 04 '23 23:01

obchardon