Wait the light to fall

🎄 2/25. 在 Raku 中 Grepping 可整除的数字

焉知非鱼

欢迎来到 Raku One-Liner Advent Calendar 的第2天! 今天, 我们将从编号为 1 的Euler 项目开始解决一个很好的任务. 我要再次提醒你, 该文的其余部分包含一个答案, 所以欢迎你暂停一下, 先考虑自己的答案。 但我几乎可以肯定, 如果你一直在阅读 raku.online, 那么你很可能在过去就已经解决了欧拉项目的问题。

任务是找到 1000 以下, 既是3的倍数, 又是5的倍数的数字的总和。我们感兴趣的行的前几个元素是 3,5,9,15,20,21等。你已经可以看到它们中的一些数字, 例如 15, 是 3和5的倍数, 因此不可能将3和5的倍数分别相加。

答案在这里:

say sum((1..999).grep: * %% (3 | 5))

现在让我们解读它。

我们需要的是过滤3的倍数或5的倍数的数字。如果你重新阅读上一句话, 铃声应该为你响起:在 Raku 中, 这可以用 Junctions 来实现, 非正式地称为量子叠加。 要测试数字是否可以被3或5整除, 请这样写:

$x %% 3 | 5

顺便说一下, %% 是 divisibility 运算符, 是一个非常好的东西, 有助于避免布尔测试中的否定, 如果你写成下面这样, 那么你只有一个百分号:

!($x % (3 | 5))

好的, 主要条件已准备就绪, 让我们扫描1和(包括)999之间的数字:

(1..999).grep: * %% (3 | 5)

这里会出现一些更有趣的 Raku 元素。 例如, WhateverCode 块, 由 * 字符引入(在我之前的 Raku Advent Calendar 的文章 All the stars of Raku 中了解更多关于它的东西)。 与冒号形式的方法调用一起, 它允许摆脱嵌套的花括号和圆括号对儿:

(1..999).grep({$_ %% (3 | 5)})

数字被过滤(如果你喜欢, 可以使用 grepped), 是时候将它们加到一块并打印结果了。 轮到本文开头所示的最后的单行了。

当然, 可以做一两个方法调用代替 say sum(...):

((1..999).grep: * %% (3 | 5)).sum.say

作为奖励,这是我的第一个答案:

sub f($n) {
    ($n <<*>> (1...1000 / $n)).grep: * < 1000
}

say (f(3)  f(5)).keys.sum;

这就是今天故事的结局! 明天再来!