在 Raku 中,如何撰寫等效于 Haskell 的span函式?
在 Haskell 中,給定一個謂詞和一個串列,可以將串列分成兩部分:
- 滿足謂詞的元素的最長前綴
- 串列的其余部分
例如,Haskell 運算式……
span (< 10) [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4]
……評估為……
([2,2,2,5,5,7],[13,9,6,2,20,4])
如何撰寫與 Haskellspan函式等效的 Raku?
更新 1
根據@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
程式輸出是……
@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)
更新 2
利用發布到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
uj5u.com熱心網友回復:
我使用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..*];
uj5u.com熱心網友回復:
一個完全天真的看法:
sub split_on(@arr, &pred) {
my @arr1;
my @arr2 = @arr;
loop {
if not &pred(@arr2.first) {
last;
}
push @arr1: @arr2.shift
}
(@arr1, @arr2);
}
創建一個新@arr1陣列并將陣列復制到@arr2. 回圈,如果陣列中的第一個元素不滿足謂詞,則為最后一次。否則,將第一個元素從 移開@arr2并將其推到@arr1.
測驗時:
my @a = [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4];
my @b = split_on @a, -> $x { $x < 10 };
say @b;
輸出是:
[[2 2 2 5 5 7] [13 9 6 2 20 4]]
這里唯一的問題是......如果不滿足謂詞怎么辦?好吧,讓我們檢查串列是否為空或不滿足謂詞來終止回圈。
sub split_on(@arr, &pred) {
my @arr1;
my @arr2 = @arr;
loop {
if !@arr2 || not &pred(@arr2.first) {
last;
}
push @arr1: @arr2.shift;
}
(@arr1, @arr2);
}
uj5u.com熱心網友回復:
在Raku (*each) 的 1 行* 中的 105 個 C 演算法的演講中, Daniel Sockwell 討論了一個幾乎可以回答您的問題的函式。我已經對其進行了一些重構以適應您的問題,但變化很小。
#| 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 { $_ < -10 }, @a; #=> ([] [2 2 2 5 5 7 13 9 6 2 20 4])
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/498435.html
下一篇:部分Html元素匯總
