use v6.e.PREVIEW; # for `snip`
my $s = "abcd";
my @ps = $s.comb.pairs;
my $res = (1..^$s.chars
==> combinations()
==> map({ @ps.snip: (&{.key < $OUTER::_} for $_) })
==> map( *>>.value>>.join ));
- get all the combinations of the enumeration of the string (except 0th) to determine the split positions
- then snip the enumeration-decorated string over those positions while generating the condition blocks on the fly
- and lastly undecorate the enumeration and join the splitted values
to get
>>> $res
((abcd) (a bcd) (ab cd) (abc d) (a b cd) (a bc d) (ab c d) (a b c d))
[other answer++ is more concise but as I understand it, it's not lazy and performs somewhat slower on larger strings, e.g., "abcd" x 5, so i'm keeping this answer.]
here are the intermediate results:
# enumerated string
>>> @ps = $s.comb.pairs
[0 => a 1 => b 2 => c 3 => d]
# combinations of the enumeration except 0s
# these are the splitting points actually
>>> $combs = (1..^$s.chars).combinations
(() (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3))
Out of these splitting points, we can generate, e.g., (*.key < 1,)
and (*.key < 1, *.key < 3)
lists so that we can pass these to @ps.snip
which will then look at the keys of its elements, i.e., index positions, and split over them for us. So the next step does this generation:
# output is actually different but this is for demonstration
>>> $combs.map({ (&{.key < $OUTER::_} for $_) })
((), (*.key < 1), (*.key < 2), (*.key < 3), (*.key < 1, *.key < 2) ... (*.key < 1, *.key < 2, *.key < 3)
(The first empty "condition" is handy to produce the string as is later, so we don't deal with that case separately.)
For each combination, e.g., (1, 2), we iterate over this (for $_
) and generate the conditions. 1 and 2 will in turn be $_
in that post-form for loop, but if we had put {.key < $_}
as a condition, the $_
won't close over those 1 and 2 but instead will be the argument passed at calling time, i.e., an enumerated pair. But we don't want that, so we say to put here the OUTER block's $_
, which will be 1 and 2 in turn. But for .key
, we do want the pair at calling time, so it's $_.key
(without the $_
as it can be omitted.)
At this point after snips we have
>>> $combs.map({ @ps.snip: (&{.key < $OUTER::_} for $_) }).raku
(((0 => "a", 1 => "b", 2 => "c", 3 => "d"),).Seq, ((0 => "a",), (1 => "b", 2 => "c", 3 => "d")).Seq, ((0 => "a", 1 => "b"), (2 => "c", 3 => "d")).Seq, ((0 => "a", 1 => "b", 2 => "c"), (3 => "d",)).Seq, ((0 => "a",), (1 => "b",), (2 => "c", 3 => "d")).Seq...)
We have the desired splits except there are extra baggages: the enumerations and the splitting to chars. So we undo the .comb.pairs
done at the beginning with >>.value>>.join
at the end, and the final result follows.