another angle is that this is analogous to the idea of “euclidean rhythm,” assuming you want clumps to be “as evenly-sized as possible” when the clump size doesn’t evenly divide the table size. (if you’d prefer a number of same-sized clumps, plus a remainder, then it is more straightforward in concept [if not implementation.])
for euclidean distribution, i like the “bucket” algo demonstrated in norns/lua/lib/er.lua.
-- clump table `x` into `n` parts, with remainder
function clump_remain(x, n)
local len = #x
local w = math.floor(len/n)
local remain = len - (w * n)
local y = {}
local src_idx = 1
for i=1,n do
local z={}
for j=1,w do
table.insert(z, x[src_idx])
src_idx = src_idx + 1
end
table.insert(y, z)
end
if remain > 0 then
local z = {}
for i=1,remain do
table.insert(z, x[src_idx])
src_idx = src_idx + 1
end
table.insert(y, z)
end
return y
end
-- clump table `x` into `n` parts, with euclidean distribution
function clump_er(x, n)
local len = #x
local y = {}
local z = {}
local b = 0
for i,v in ipairs(x) do
table.insert(z, v)
b = b + n
if b > len then
table.insert(y, z)
z = {}
b = b - len
end
end
if #z > 0 then table.insert(y, z) end
return y
end
function print_clumps(y)
for _,v in pairs(y) do
print("{")
for _,w in pairs(v) do
print(" " .. w)
end
print("}")
end
end
given x = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} and n=4,
y = clump_remain(x, n) yields {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10, 11}}
and y = clump_er(x, n) yields {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11}},|
[update: cleaned up and fixed clump_remain function.]
PS: i believe i’ve mentioned this previously in this very thread, but: i’d avoid the use of the modulo operator in general unless you are specifically looking for a % b == a - math.floor(a/b)*b. (that is the literal underlying implementation of lua’s %. i see people trying to use it to “optimize” loop bookkeeping, where it usually will have the opposite effect.)