Subsets of a list
I would use:
data = {1, 20, 3, 40};
Join @@ Permutations /@ IntegerPartitions[Length@data];
results = Internal`PartitionRagged[data, #] & /@ %
{{4}, {3, 1}, {1, 3}, {2, 2}, {2, 1, 1}, {1, 2, 1}, {1, 1, 2}, {1, 1, 1, 1}} {{{1, 20, 3, 40}}, {{1, 20, 3}, {40}}, {{1}, {20, 3, 40}}, {{1, 20}, {3, 40}}, {{1, 20}, {3}, {40}}, {{1}, {20, 3}, {40}}, {{1}, {20}, {3, 40}}, {{1}, {20}, {3}, {40}}}
IntegerPartitions
is used get the ways in which you can split a list, to be used with the function above. Permutations
is used to get all orders of these. By the way, you could use the function Compositions
from the Combinatorica package in place of both of these if you want to include zeros.
These specifications are fed to Internal`PartitionRagged
which splits a list into given lengths, e.g. [{1,2,3,4,5}, {2,1,2}]
-> {{1,2}, {3}, {4,5}}
. Users of Mathematica versions prior to 8 can use my dynamicPartition
function in its place.
You might generate all subsets by placing special markers (asterisks) where a list should be split.
data = {1, 20, 3, 40};
(* The asterisks "*" indicate where a list should be split *)
data1 = Insert[data, "*", #] & /@ (Subsets[Range[2, Length[data]]] /. a_Integer :> {a})
(* out *)
{{1, 20, 3, 40}, {1, "*", 20, 3, 40}, {1, 20, "*", 3, 40}, {1, 20, 3, "*", 40},
{1, "*", 20, "*", 3, 40}, {1, "*", 20, 3, "*", 40}, {1, 20, "*", 3, "*", 40},
{1, "*", 20, "*", 3, "*", 40}}
(* s actually does the splitting *)
s[list_] := Split[list, # =!= "*" &]
(* t removes asterisks *)
t[list_] := DeleteCases[#, "*"] & /@ list
t[#] & /@ (s[#] & /@ data1)
(* out *)
{{{1, 20, 3, 40}}, {{1}, {20, 3, 40}}, {{1, 20}, {3, 40}}, {{1, 20, 3}, {40}},
{{1}, {20}, {3, 40}}, {{1}, {20, 3}, {40}},
{{1, 20}, {3}, {40}}, {{1}, {20}, {3}, {40}}}
Note
The following snippet targeted all the positions in data
where splits could be made:
Subsets[Range[2, Length[data]]]
(* out *)
{{}, {2}, {3}, {4}, {2, 3}, {2, 4}, {3, 4}, {2, 3, 4}}
So the first list had no splits; the second list was split at position 2, that is, after the first element; the third list was split at position 3; ... and the final list was split at positions 2, 3 and 4.
data = {1, 20, 3, 40};
i = Join @@ Permutations /@ IntegerPartitions[Length[data]];
In version 11.2 TakeList
is introduced which does the same thing as Internal'PartitionRagged
plus more. But even though TakeList
has more functionality, it evaluates much faster:
Do[Internal`PartitionRagged[data, #] & /@ i, {1000}] // RepeatedTiming
Do[ TakeList[data, #] & /@ i, {1000}] // RepeatedTiming
{0.337, Null}
{0.0210, Null}