如何在Perl 6中计算整数的数字交替和?

5

如果一个数字的各位数字交替求和为11的倍数,则该数字可以被11整除。

例如,如果数字为1595,则+1-5+9-5==0,因此1595可以被11整除。如何实现这样的求和?以下是我的解决方案,但它过于复杂,而且仅适用于位数为偶数的数字。

my $number = 1595;
say [+] $number.comb.map({$^a - $^b});

什么是最佳实践?

1
关于您的解决方案(我喜欢,顺便说一下)有一个小问题:如果数字位数为奇数,则会出现“传递的位置参数太少;期望2个参数但只得到1个”的错误。您可以通过将签名更改为块来解决此问题:say [+] "15956".comb.map(-> $a, $b = 0 {$a - $b}); # 6 - Elizabeth Mattijsen
@ElizabethMattijsen 谢谢!我觉得我应该给 $^b 一个默认值,但不知道如何实现。 - Eugene Barsky
@ElizabethMattijsen 那么下面这个可能会更容易一些,因为它不需要默认值。 :) say [+] 15956.comb.kv.map({ $^b * (-1) ** $^a}) - Eugene Barsky
4个回答

6
say [+] 1595.comb Z* (1, -1, 1 ... *)

简单来说:.comb返回一个字符列表,Z*将该列表逐个元素与RHS上的序列相乘。

这个序列是一个几何序列,...系列运算符可以从三个元素中推断出来。由于zip运算符Z停止于最短的序列,我们不必担心终止RHS上的序列。

另一种写法是:

say [+] 1595.comb Z* (1, -* ... *)

-*是对上一个值的显式否定,应用于初始元素以生成下一个元素。

您也可以将其写成

say [+] 1595.comb Z* (1, &prefix:<-> ... *)

哦,我感觉应该有一个优雅的解决方案!不知道如何实现 1,-1,1...,它非常有用! - Eugene Barsky

5

Moritz使用的十字架很有趣(也很令人愉悦),但你也可以使用列表块。这是接近你最初尝试的方式。 我认为你是朝着转子方向前进:

my $number = 1595;
say  [+] $number.comb.rotor(2, :partial).map: { $^a.[0] - ($^a.[1] // 0) }

请注意,您的块只有一个参数。那就是列表。这有点丑陋,因为奇数位的情况会使 $^a.[1] 变成 Nil,这将产生警告。

现在我对此进行了更多的尝试,我使用签名来处理它,以便可以给 $b 设置默认值。这样会好得多:

my $number = 1595;
say  [+] $number
    .comb
    .rotor(2, :partial)
    .map: -> ( $a, $b = 0 ) { $a - $b }

但是你甚至不需要 rotor,因为 map 将获取它所需的所有位置参数(感谢评论中的 timotimo)。这意味着你非常接近,只是错过了签名:

my $number = 1595;
say  [+] $number
    .comb
    .map: -> ( $a, $b = 0 ) { $a - $b }

您在评论中提供的解决方案对于奇数位数字情况不太适用:

say [+] $number.comb.rotor(2, :partial).map({[-] $_});

我知道这个问题并不完全涉及除数,但我很高兴Perl 6有一个“可被整除”运算符,即%%

$ perl6
> 121 %% 11
True
> 122 %% 11
False
> 1595 %% 11
True
> 1596 %% 11
False

谢谢,我不知道这个!那么以下解决方案呢?say [+] $number.comb.rotor(2, :partial).map({[-] $_} - Eugene Barsky
谢谢!是的,我错了:[-] (1)会得到-1(我本以为会得到1)。 - Eugene Barsky
2
这里不需要使用.rotor(2, :partial).map(($a, $b = 0) -> {}),只需使用.map(-> $a, $b = 0 { })即可达到相同的效果。 - timotimo
@timotimo 至少这让我了解了“rotor”的知识。 :) - Eugene Barsky
@briandfoy 这是我的新变体,希望它是正确的。say [+] 15956.comb.kv.map({ $^b * (-1) ** $^a}) - Eugene Barsky
@briandfoy 这也可以运行 :) say [+] 15956.comb.kv.map( (-1) ** * * *) - Eugene Barsky

3
say [+] 1595.comb >>*>> (1,-1)

类似于Z*版本,但在右侧使用超级元算符循环效果(如果左侧少于2个数字,则无需担心)。


可能,这是最好的解决方案! - Eugene Barsky

2
这是我的解决方案。
say [+] 15956.comb.kv.map( (-1) ** * * * ); # 6

并且有一个更加详细的版本。

say [+] 15956.comb.kv.map({ $^b * (-1) ** $^a }); # 6

更新:又有一个解决方案。

say - [+] 15956.comb(2)>>.comb.map({[R-] $_}); # 6

1
数学。另一个更明确的版本:say [+] 15956.comb.pairs».&{ (-1) ** .key * .value }。其中.kv返回一个由2个元素列表组成的列表,.pairs返回一个Pair列表。而.map通过将N个元素一次传递给其右侧的操作来惰性地消耗左侧的列表,»(ASCII中的>>)通过在列表上运行其右侧的操作来急切地消耗左侧的列表,对列表中的每个单个元素进行并行处理(在多个核心、GPU或使用某些其他 SIMD方法),如果编译器决定这样做的话。 - raiph
@raiph 谢谢!您可以解释一下 .& 的含义吗?.& 在文档中的链接好像失效了。这里有些解释,但我不敢保证我完全理解它是如何工作的。 :) - Eugene Barsky
1
@EugeneBarsky 后缀 . 表示方法调用。 "内联方法" 是 &{...}。这是一个闭包,将传递一个参数,即调用者。语法是 .&{...} 而不仅仅是 .{...},因为后者是哈希下标,与没有 . 的后缀(实际上是后置圆括号){...} 相同。消除歧义的字符是 &,因为后者是适当的 sigil(它表示例程)。 - raiph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接