Partition list into $n$ sublists

Is there an inbuilt function/option or an elegant composition of functions for partitioning a list into exactly $n$ sublists? I played around with Partition and its options but could not find anything suitable by itself. The general requirement is that the Length of the resulting splitted list is $n$. A few interesting corner cases:

• Splitting a list into $n=1$ parts should result in the list wrapped with List, e.g. splitting {1,2,3} into $n=1$ parts yields {{1,2,3}} because Length[{{1,2,3}}] is 1
• Splitting lists with fewer than $n$ elements by padding with empty lists e.g. {1,2}into $n=3$ parts should yield {{1}, {2}, {}}
• Splitting lists of uneven length into an even number of parts or vice versa e.g. {1,2,3} into $n=2$ parts should either yield {{1,2},{3}} or {{1}, {2,3}}. It doesn't matter to me which, but behavior should be consistent.

Right now I use

ClearAll@splitList;
splitList[1][list_] := {list};
splitList[parts_Integer][list_] :=
With[{n = Ceiling[Length[list]/parts]},
Partition[list, UpTo[n]] //
Replace[
{prev : Repeated[{___}, parts - 1]} :>
{prev, Apply[Sequence]@Table[{}, {parts - Length@{prev}}] }
]
]


I feel that the concept of splitting a list into exactly $n$ sublists is something that is easy to express but involves difficult corner cases and thus could be something that is already implemented in Mathematica, much like with regular Partition and UpTo.

• In your program, splitList[4][Range[9]] returns {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {}} is it intended? How about {{1,2,3,4,5,6,7,8,9},{},{},{}}? Mar 28, 2017 at 8:34
• @happy fish thanks for this observation; this is yet another corner case that is ill defined and does depend on what one wishes to accomplish. My application uses only needs the special case $n=2$ and I want chunks of equal size where possible but any solution is interesting in the scope of this broader question. In a build-in function I would expect the partitioning scheme as an option. Mar 28, 2017 at 8:41
• @happyfish, yes your code is a possible solution Mar 28, 2017 at 8:44
• OK, I undeleted my answer. But I think it is not very contributive after all... Mar 28, 2017 at 8:45

This seems to return same results as your code:

ms = PadRight[Partition[#, UpTo[Ceiling[Length[#]/#2]]], #2, {{}}]&;


Check:

r1 = splitList[#][{1, 2, 3, 4, 5, 6}] & /@ Range[1, 10];
r2 = ms[{1, 2, 3, 4, 5, 6}, #] & /@ Range[1, 10];
r1 == r2


True

ArrayReshape seems quite clean to my eye, even with replacement for null padding. It also works in v9.0 and after, whereas UpTo was introduced in v10.3.

Module[{x},
splitIn[p_Integer?Positive][a_?ListQ] :=
ArrayReshape[a, {p, ⌈Length@a/p⌉}, x] /. x -> Sequence[]
]

• Also DeleteCases[ ArrayReshape[a, {p, \[LeftCeiling]Length@a/p\[RightCeiling]}, x], x, 2] ... +1 Nov 4, 2019 at 3:01

This seems to do the job:

spl[lst_, n_] := TakeList[lst, Subdivide[1, Length@lst + 1, n] // Round // Differences];


I am not sure I have understood this. Perhaps this will motivate clarification or the correct or better answer:

f[a_, n_] :=
Module[{a2}, (If[n > Length[a], a2 = PadRight[a, n], a2 = a];
InternalPartitionRagged[a2, #] & /@
Permutations[IntegerPartitions[Length[a2], {n}][[1]]] /. {0 ->
Sequence[]})]


e.g. Grid[{Range@#, f[Range@#, 4]} & /@ Range[3, 10]]:

A simpler version.

p[list_, n_] :=
Module[{res = Partition[list, UpTo[Ceiling[Length[list]/n]]]},
Join[res, Table[{}, n - Length[res]]]]


Assuming {} should only be used when n is greater than Length[list]:

split[L_, n_] := PadRight[MapThread[L[[Span[##]]] &, {Most[# + 1], Rest[#]} &[
Round[Range[0, #, Max[#/n, 1]] &[Length[L]]]]], {n}, {{}}]

list = Range[17];
p[list, 1]
p[list, 12]
p[list, 25]
`

{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}}

{{1}, {2, 3}, {4}, {5, 6}, {7}, {8}, {9, 10}, {11}, {12, 13}, {14}, {15, 16}, {17}}

{{1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}, \ {14}, {15}, {16}, {17}, {}, {}, {}, {}, {}, {}, {}, {}}