🎄 15/25. 在 Raku 中使用斐波那契数
— 焉知非鱼欢迎来到 Raku One-Liner Advent Calendar 的第15天!今天,将有两个单行程序,它们都产生斐波纳契数。
是的,最有可能的是,你从未在实际代码中使用过这样的数字,而且,很可能,你用它们解决了许多教育问题。然而,今天,让我们解决欧拉项目的问题25,并尝试在 Code-Golf.io 站点上寻找最短的 Fibonacci 问题解决方案。
Pre-party #
我们如何在 Raku 中形成 Fibonacci 序列呢?使用序列运算符 ...
:
0, 1, * + * ... *
如果你想在代码中有一些奇特的味道,你可以用 Inf
或 ∞
替换最后的那个星号。在任何情况下,结果都是 Seq
类型的惰性序列。 Raku 不会立即计算它(并且它不能,因为右边缘是无限的)。
第1部分 #
第一个任务是找到第一个 Fibonacci 数的索引,该数字有 1000 个数字。当然,你可以循环上面创建的序列并自己跟踪索引。但是在 Raku 中,有一个选项可以修改 grep
例程簇,并要求它返回匹配项的索引而不是项本身。
另外,我们将使用更合适的方法 first
代替 grep
。如果我们用 k
键调用该方法,它将返回第一个匹配项或其索引。仅仅提到键就足够了,真的不需要值。
say (0, 1, * + * ... *).first(*.chars >= 1000, :k)
该程序打印一个整数,这是给定问题的正确答案。
第2部分 #
现在让我们解决一个高尔夫任务并打印前30个斐波那契数字,用单行程序。这次,我们必须在代码中使用尽可能少的字符。
第一种方法相当冗长(即使使用 ^31
代替 0..30
,它需要 33 个字符):
.say for (0, 1, * + * ... *)[^31]
可以压缩一些空间。当然,第一个也是最明显的就是删除空格(剩下28个字符):
.say for (0,1,*+*...*)[^31]
另一个有趣的技巧是使用 >>
meta-operator 在序列的每个元素上调用 say
方法。它将代码进一步压缩为24个字符:
(0,1,*+*...*)[^31]>>.say
此时,我们可以使用一些 Unicode,并节省三个以上的字符(左21):
(0,1,*+*…*)[^31]».say
看起来已经够紧凑了,但仍有一些选项可供尝试。让我们摆脱显式切片,并尝试在最后一个元素处停止序列:
(0,1,*+*…*>514229)».say
代码变得更长(23个字符),但我们这里不需要确切的数字 514229。给出一些数字就足够了,这个数字比第29个更大,然后小于序列的第30个元素。例如,它可以是 823543,它是7的7次幂。使用上标(19个字符)来写:
(0,1,*+*…*>7⁷)».say
最后,通过在单个字符中使用另一个代表 800000 的 Unicode 字符,可以减少一个字符。并非每个(如果有的话)字体都能显示出具有视觉吸引力的东西,但 Raku 能识别该字符:
(0,1,*+*…*>𐧴)».say
这18个字符比Gode-Golf的第一名多一个字符。我有一种感觉,你可以通过用 ^2
替换序列的前两个元素来节省另一个字符,但这在当前的Rakudo中不起作用,你必须多用一个字符来展平列表:|^2
,这使得答案再次变成18个字符。
希望删除条件中的 *>
部分以停止序列并用固定数字替换它。不幸的是,没有办法用1到90之间的数字的幂来表示 832040。这是可能的,我们可以使用上标来计算数字。
另一个想法是使用正则表达式,但我们需要至少四个字符,这没有帮助:
(0,1,*+*…/20/)».say
让我今天到此为止。你是否碰巧创建了一个更短的答案,请在下方评论。明天见!