检查列表的所有元素是否在 Raku 中都是素数

Lar*_*een 7 mapreduce raku

my @g = (1,2,3,4);
say reduce {is-prime}, @g; # ==> gives error
say reduce {is-prime *}, @g; #==> gives error
say reduce {is-prime}, (1,2,3,4); # ==> gives error
say so is-prime @g.all; # ==> gives error
Run Code Online (Sandbox Code Playgroud)

如何检查列表中的所有元素是否在 Raku 中都是素数?

jjm*_*elo 9

上面的答案都很有帮助,但它们无法解释为什么您的解决方案不起作用。基本上,reduce不会对列表的每个成员应用函数(在您的情况下,是素数)。你想要地图。错误说

Calling is-prime() will never work with signature of the proto ($, *%)
Run Code Online (Sandbox Code Playgroud)

因为reduce需要一个中缀,因此二进制,函数,或带有两个参数的函数;它所做的是将它们应用于第一对元素,然后应用于结果和第三个元素,依此类推。由于类似的原因,最后一条语句不起作用:您使用列表参数而不是单个参数调用 is-prime。


Eli*_*sen 6

您基本上是在问:此列表中是否有任何不是素数的元素?我会这样写:

say "not all prime" if @g.first: !*.is-prime;
Run Code Online (Sandbox Code Playgroud)

请注意:虽然,显然1不是素数,根据所考虑的is-prime功能:

say 1.is-prime;  # False
Run Code Online (Sandbox Code Playgroud)

所以在你的例子中first会在1上触发,而不是在4上触发。


acw*_*acw 5

当然有可能的方法来做到这一点。一个非常明确的方法是使用 for 循环:

for @g -> $g {
 if $g.is-prime {
  say $g;
 }
}
Run Code Online (Sandbox Code Playgroud)

或者使用 grep (您可以保留 $_ 隐式):

@g.grep({ $_.is-prime }).say
Run Code Online (Sandbox Code Playgroud)

以上两者都假设您真的想过滤掉素数。当然,您也可以真正检查每个数字并获得一个布尔值:

@g.map({ .is-prime }).say
Run Code Online (Sandbox Code Playgroud)


Bra*_*ert 5

这有一个很大的问题:

say reduce {is-prime}, @g;
Run Code Online (Sandbox Code Playgroud)

您创建了一个 lambda:

{  }
Run Code Online (Sandbox Code Playgroud)

它唯一能做的就是调用一个函数:

is-prime
Run Code Online (Sandbox Code Playgroud)

你没有给函数任何参数。
是否应该只是猜测参数应该是什么?

如果您打算is-prime作为参考传入,则应该使用&is-prime而不是{is-prime}. 当然,那仍然行不通。

另一个问题是reduce通过递归组合值来操作。
如果它一次只处理一个参数,它就不能这样做。
裸块 lambda{}接受零个或一个参数,而不是两个或更多。


reduce经常与map.

它经常发生,以至于有一个关于MapReduce的维基百科页面。

say ( map &is-prime, @g ==> reduce { $^a and $^b } );
# False

say ( map &is-prime, 2,3,5 ==> reduce { $^a and $^b } );
# True
Run Code Online (Sandbox Code Playgroud)

我是这样写的,所以它map会在之前的行中reduce,但也许这样会更清楚:

say reduce {$^a and $^b}, map &is-prime, 2,3,5;
# True
Run Code Online (Sandbox Code Playgroud)

reduce 使用中缀运算符非常常见,因此有一种更短的写法。

say [and] map &is-prime, 2,3,5;
# True
Run Code Online (Sandbox Code Playgroud)

当然,最好只找到第一个不是质数的值,然后说相反。

因为即使有一个不是素数的值也意味着它们不可能都是素数。

不过你必须小心,因为你可能认为这样的事情总是有效的:

not @g.first: !*.is-prime;
Run Code Online (Sandbox Code Playgroud)

它确实适用于您赋予它的价值,但可能并非总是如此。如果找不到值则
first返回Nil

not (2,3,5).first: !*.is-prime;
# not Nil === True

not (2,3,4).first: !*.is-prime;
# not 4   === False

not (2,3,0,4).first: !*.is-prime;
# not 0   === True
Run Code Online (Sandbox Code Playgroud)

最后一个返回0,当与not返回结合使用时True

你可以用defined.

not defined (2,3,0,4).first: !*.is-prime;
# False
Run Code Online (Sandbox Code Playgroud)

这仅在first不返回碰巧在列表中的未定义元素时才有效。

(Int,Any).first: Real
# Int

defined (Int,Any).first: Real
# False
Run Code Online (Sandbox Code Playgroud)

您可以通过要求索引而不是值来解决这个问题。
你当然还需要defined

(Int,Any).first: :k, Real
# 0

defined (Int,Any).first: :k, Real
# True
Run Code Online (Sandbox Code Playgroud)

修复它的另一种方法是使用grep.

not (2,3,0,4).grep: !*.is-prime;
# not (0,4) === False
Run Code Online (Sandbox Code Playgroud)

由于grep总是返回 a List,您不必担心检查0或未定义的元素。
(AListTrue如果它包含任何元素,无论值是什么。)

grep足够聪明,知道如果你强制Bool它可以在找到第一个值时停止。因此,它的短路与您使用first.


这导致了一些相当时髦的代码,带有这两个否定运算符。所以应该放到一个函数中。

sub all-prime ( +@_ ) {
  # return False if we find any non-prime
  not @_.grep: !*.is-prime
  # grep short-circuits in Bool context, so this will stop early
}
Run Code Online (Sandbox Code Playgroud)

如果你给它一些奇怪的东西,这仍然可能失败

all-prime 2,3,5, Date.today;
# ERROR: No such method 'is-prime' for invocant of type 'Date'
Run Code Online (Sandbox Code Playgroud)

如果您关心,请添加一些错误处理。

sub all-prime ( +@_ ) {
  # return Nil if there was an error
  CATCH { default { return Nil }}

  # return False if we find any non-prime
  not @_.grep: !*.is-prime
}

all-prime 2,3,5, Date.today;
# Nil
Run Code Online (Sandbox Code Playgroud)