In Raku, how does one write the equivalent of Haskell's span
function?
In Haskell, given a predicate and a list, one can split the list into two parts:
- the longest prefix of elements satisfying the predicate
- the remainder of the list
For example, the Haskell expression …
span (< 10) [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4]
… evaluates to …
([2,2,2,5,5,7],[13,9,6,2,20,4])
How does one write the Raku equivalent of Haskell's span
function?
CodePudding user response:
I use first
method and :k
adverb:
my @num = [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4];
my $idx = @num.first(* > 10):k;
@num[0..$idx-1], @num[$idx..*];
CodePudding user response:
A completely naive take on this:
sub split_on(@arr, &pred) {
my @arr1;
my @arr2 = @arr;
loop {
if not &pred(@arr2.first) {
last;
}
push @arr1: @arr2.shift
}
(@arr1, @arr2);
}
Create a new @arr1
and copy the array into @arr2
. Loop, and if the predicate is not met for the first element in the array, it's the last time through. Otherwise, shift the first element off from @arr2
and push it onto @arr1
.
When testing this:
my @a = [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4];
my @b = split_on @a, -> $x { $x < 10 };
say @b;
The output is:
[[2 2 2 5 5 7] [13 9 6 2 20 4]]
Only problem here is... what if the predicate isn't met? Well, let's check if the list is empty or the predicate isn't met to terminate the loop.
sub split_on(@arr, &pred) {
my @arr1;
my @arr2 = @arr;
loop {
if !@arr2 || not &pred(@arr2.first) {
last;
}
push @arr1: @arr2.shift;
}
(@arr1, @arr2);
}