[英]In Raku, how does one write the equivalent of Haskell's span function?
In Raku, how does one write the equivalent of Haskell's span
function?在 Raku 中,如何编写等效于 Haskell 的
span
函数?
In Haskell, given a predicate and a list, one can split the list into two parts:在 Haskell 中,给定一个谓词和一个列表,可以将列表分成两部分:
For example, the Haskell expression …例如,Haskell 表达式……
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?如何编写与 Haskell 的
span
函数等效的 Raku?
Based on the answer of @chenyf, I developed the following span
subroutine (additional later update reflects negated predicate within span
required to remain faithful to the positive logic of Haskell's span
function ) …根据@chenyf 的回答,我开发了以下
span
子例程(稍后的附加更新反映了span
内的否定谓词需要保持忠实于Haskell 的span
函数的正逻辑)......
sub span( &predicate, @numberList )
{
my &negatedPredicate = { ! &predicate($^x) } ;
my $idx = @numberList.first(&negatedPredicate):k ;
my @lst is Array[List] = @numberList[0..$idx-1], @numberList[$idx..*] ;
@lst ;
} # end sub span
sub MAIN()
{
my &myPredicate = { $_ <= 10 } ;
my @myNumberList is Array[Int] = [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4] ;
my @result is Array[List] = span( &myPredicate, @myNumberList ) ;
say '@result is ...' ;
say @result ;
say '@result[0] is ...' ;
say @result[0] ;
say @result[0].WHAT ;
say '@result[1] is ...' ;
say @result[1] ;
say @result[1].WHAT ;
} # end sub MAIN
Program output is …程序输出是……
@result is ...
[(2 2 2 5 5 7) (13 9 6 2 20 4)]
@result[0] is ...
(2 2 2 5 5 7)
(List)
@result[1] is ...
(13 9 6 2 20 4)
(List)
Utilizing information posted to StackOverflow concerning Raku's Nil
, the following updated draft of subroutine span
is …利用发布到StackOverflow上的有关 Raku 的
Nil
的信息,以下子例程span
的更新草案是……
sub span( &predicate, @numberList )
{
my &negatedPredicate = { ! &predicate($^x) } ;
my $idx = @numberList.first( &negatedPredicate ):k ;
if Nil ~~ any($idx) { $idx = @numberList.elems ; }
my List $returnList = (@numberList[0..$idx-1], @numberList[$idx..*]) ;
$returnList ;
} # end sub span
sub MAIN()
{
say span( { $_ == 0 }, [2, 2, 5, 7, 4, 0] ) ; # (() (2 2 5 7 4 0))
say span( { $_ < 6 }, (2, 2, 5, 7, 4, 0) ) ; # ((2 2 5) (7 4 0))
say span( { $_ != 9 }, [2, 2, 5, 7, 4, 0] ) ; # ((2 2 5 7 4 0) ())
} # end sub MAIN
I use first
method and :k
adverb, like this:我使用
first
一种方法和:k
副词,如下所示:
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..*];
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
.创建一个新的
@arr1
并将数组复制到@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
.否则,将第一个元素从
@arr2
移出并将其推送到@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);
}
In his presentation 105 C++ Algorithms in 1 line* of Raku (*each) Daniel Sockwell discusses a function that almost answers your question.在Raku (*each) 的 1 行* 中的 105 个 C++ 算法的演讲中,Daniel Sockwell 讨论了一个几乎可以回答您的问题的函数。 I've refactored it a bit to fit your question, but the changes are minor.
我已经对其进行了一些重构以适应您的问题,但变化很小。
#| Return the index at which the list splits given a predicate.
sub partition-point(&p, @xs) {
my \zt = @xs.&{ $_ Z .skip };
my \mm = zt.map({ &p(.[0]) and !&p(.[1]) });
my \nn = mm <<&&>> @xs.keys;
return nn.first(?*)
}
#| Given a predicate p and a list xs, returns a tuple where first element is
#| longest prefix (possibly empty) of xs of elements that satisfy p and second
#| element is the remainder of the list.
sub span(&p, @xs) {
my \idx = partition-point &p, @xs;
idx.defined ?? (@xs[0..idx], @xs[idx^..*]) !! ([], @xs)
}
my @a = 2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4;
say span { $_ < 10 }, @a; #=> ((2 2 2 5 5 7) (13 9 6 2 20 4))
say span { $_ < 5 }, [6, 7, 8, 1, 2, 3]; #=> ([] [6 7 8 1 2 3])
So I figured I'd throw my version in because I thought that classify
could be helpful :所以我想我会把我的版本扔进去,因为我认为
classify
可能会有所帮助:
sub span( &predicate, @list ) {
@list
.classify({
state $f = True;
$f &&= &predicate($_);
$f.Int;
}){1,0}
.map( {$_ // []} )
}
The map
at the end is to handle the situation where either the predicate is never or always true.最后的
map
用于处理谓词永远不为真或总是为真的情况。
Version 6.e of raku will sport the new 'snip' function:版本 6.e 的 raku 将采用新的“snip”功能:
use v6.e;
dd (^10).snip( < 5 );
#«((0, 1, 2, 3, 4), (5, 6, 7, 8, 9)).Seq»
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.