在列表中§
有关例程 reduce 的主要文档,请参阅上下文
multi method reduce(Any: )multi reduce (, +list)
通过迭代应用知道如何组合两个值的例程,从任意多个值的列表中返回单个“组合”值。除了子例程和列表之外,还可以提供初始值来初始化 reduce,如果列表为空,该值最终将成为返回值。因此,reduce f, init, list
从左到右组合列表的元素,如下面的伪代码所示
result0 = init result1 = f(result0, list[0]) result2 = f(result1, list[1]) ... resultn = f(resultn-1, list[n-1])
resultn
是 n 元素列表的最终结果。
say reduce :<+>, (1, 2, 3); # OUTPUT: «6»say (1, 2, 3).reduce: :<+>; # OUTPUT: «6»say reduce , (5, 9, 12, 1); # OUTPUT: «12»
如果 list
仅包含单个元素,则运算符将应用于该单个元素(如果可能);否则,它将返回元素本身。
say reduce :<->, (10,); # OUTPUT: «10»
当列表不包含任何元素时,将引发异常,除非 &with
是一个具有已知标识值的_运算符_(例如,infix:<+>
的标识值为 0)。因此,建议您在输入列表前添加初始值(或显式标识值)。
my \strings = "One good string!", "And one another good string!";say reduce , '', |strings; # like strings.joinmy \numbers = 1, 2, 3, 4, 5;say reduce , 0, |numbers; # like numbers.maxsub count-and-sum-evens( (Int \count, Int \sum), Int \x )say reduce , (0, 0), |numbers; # OUTPUT: «(2 6)»
在最后一个示例中,由于 reduce
仅支持一个初始值,因此我们使用包含两个值的 List
,它本身就是一个值。 count-and-sum-evens
子例程接受两个位置值:一个包含两个 Int
的 List
和一个 Int
,并返回一个存储累积的偶数整数的计数和总和的 List
。
如果 &with
是_运算符_的代码对象,则将遵循其固有的标识值和结合性 - 换句话说,(VAL1, VAL2, VAL3).reduce(&infix:<OP>)
与 VAL1 OP VAL2 OP VAL3
相同,即使对于非左结合运算符也是如此。
# Raise 2 to the 81st power, because 3 to the 4th power is 81(2,3,4).reduce(:<**>).lsb.say; # OUTPUT: «81»(2**(3**4)).lsb.say; # OUTPUT: «81»(2**3**4).lsb.say; # OUTPUT: «81»# Subtract 4 from -1, because 2 minus 3 is -1(2,3,4).reduce(:<->).say; # OUTPUT: «-5»((2-3)-4).say; # OUTPUT: «-5»(2-3-4).say; # OUTPUT: «-5»
由于使用中缀运算符进行 reduce 是一种常见操作,因此 reduce 元运算符 [ ]
提供了一种语法快捷方式。因此,无需将运算符的代码对象传递给 reduce
,只需将运算符直接传递给 [ ]
。要改用用户定义的子例程,请在子例程的代码对象周围再加一层方括号。
say [*] (1, 2, 3, 4); # OUTPUT: «24»say [min] (4, 2, 1, 3); # OUTPUT: «1»sub mult ;say [[]] (1, 2, 3, 4); # OUTPUT: «24»
从语义上讲,以下所有操作都执行相同的操作。
my \numbers = 1, 2, 3, 4, 5;say reduce , 0, |numbers;say reduce * + *, 0, |numbers;say reduce &[+], numbers; # operator does not need explicit identity valuesay [+] numbers;
由于 reduce
是一个隐式循环,它使用其_reduce_子例程进行迭代,因此它会响应 &with
中的 next
、last
和 redo
语句。
sub last-after-seven ;say (2, 3, 4, 5).reduce: ; # OUTPUT: «9»
reduce
是从左到右还是从右到左累积元素取决于运算符。在函数式编程领域,此操作通常称为 fold。对于右结合运算符,它是_右折叠_,否则(通常)它是_左折叠_。在 Raku 中,您可以使用 is assoc
指定运算符的结合性。
sub infix:<foo>(, ) is assoc<right>say [foo] 1, 2, 3, 4; # OUTPUT: «(1, (2, (3, 4)))»sub infix:<bar>(, ) is assoc<left>say [bar] 1, 2, 3, 4; # OUTPUT: «(((1, 2), 3), 4)»
**实际示例 1:** 在此示例中,我们使用 reduce
生成一个随机数学公式(例如,“(4 + ((3 * x) + 11) / 6))”)。
my = [Z] (<+ - * />, 1..20)».roll(4);say ('x', |).reduce: -> , [, ]
**实际示例 2:** 假设我们有一个多项式,表示为整数系数列表 c[n-1]、c[n-2]、...、c[0],其中 c[i] 是 xi 的系数。我们可以使用 map
和 reduce
对其进行如下评估。
sub evaluate(List \c where c.all ~~ Int, Rat \x --> Rat)my \c = 2, 3, 1; # 2x² + 3x + 1say evaluate c, 3.0; # OUTPUT: «28»say evaluate c, 10.0; # OUTPUT: «231»
在 Supply 中§
有关 method reduce 的主要文档,请参阅上下文。
method reduce(Supply: --> Supply)
创建一个“reduce”供应,它将发出具有与 List.reduce 相同语义的单个值。
my = Supply.from-list(1..5).reduce();.tap(-> ); # OUTPUT: «15»
在 Any 中§
有关 routine reduce 的主要文档,请参阅上下文。
multi method reduce(Any: & --> Nil)multi method reduce(Any: )multi reduce (, +list)
此例程通过应用二元子例程组合列表对象中的元素,并生成单个结果。它将其参数(或子例程形式的第一个参数)作为运算符应用于对象中的所有元素(或子例程形式的第二个参数),从而生成单个结果。子例程必须是 中缀运算符 或接受两个位置参数。使用中缀运算符时,我们必须提供其子例程版本的代码对象,即运算符类别,后跟冒号,然后是带有构成运算符的符号的列表引用结构(例如,infix:<+>
)。请参阅运算符。
say (1..4).reduce(:<+>); # OUTPUT: «10»say reduce :<+>, 1..4; # OUTPUT: «10»say reduce , 1..4; # OUTPUT: «1»sub hyphenate(Str \a, Str \b)say reduce , 'a'..'c'; # OUTPUT: «a-b-c»
应用于类时,例程将始终返回 Nil
。
say Range.reduce(:<+>); # OUTPUT: «Nil»say Str.reduce(:<~>); # OUTPUT: «Nil»
有关更详细的讨论,请参阅 List.reduce。