【问题标题】:Haskell - list comprehension can't enumerate N × NHaskell - 列表理解不能枚举 N × N
【发布时间】:2013-05-14 20:53:56
【问题描述】:

我必须编写一个函数,它返回所有对 (x,y) 的列表,其中 x, y ∈ N , and:

  • x 是两个自然数的乘积 (x = a • b, 其中 a, b ∈ N)
  • x 确实大于 5 但确实小于 500,
  • y 是一个平方数(y = c² 其中 c ∈ N)不大于 1000,and
  • x 是 y 的除数。

我的尝试:

listPairs :: [(Int, Int)] 
listPairs = [(a*b, y) | y <- [0..], a <- [0..], b <- [0..], 
                        (a*b) > 5, (a*b) < 500, (y*y) < 1001, 
                        mod y (a*b) == 0]

但它不返回任何东西,并且计算机在它上面工作了很多。

但是,如果我为 aby 选择较小的范围,则 e。 G。 [0..400],最多需要一分钟,但它会返回正确的结果。

那么我该如何解决性能问题呢?

【问题讨论】:

  • -1 您已经从 Haskell 咖啡馆获得了大量帮助,请不要从一个站点到另一个站点寻求帮助(Danny Gratzer)
  • 对于那些不知道我在说什么的人来说,这是由 OP 提出的,今天下午已经详细回答了 (groups.google.com/forum/?fromgroups=#!topic/haskell-cafe/…)
  • 400 太低。你应该确保你没有错过任何正确的解决方案:(a*b)&lt;500, (a*b)&gt;5, a==1, b==499 是一致的。所以使用[1..499]0*x &gt; 5 永远不会是真的)。 OTOH (y*y) &lt; 1001 ==> y &lt; 32 所以使用y&lt;-[1..31], a&lt;-[1..499]。应该让它快 32 倍。然后,a*b &lt; 500a*b==b*a 所以使用b&lt;-[a..min 499 (div 500 a)] 这让我们的问题规模又大大减少了。现在只需不到一秒钟。
  • 顺便说一句,根据您的描述,您应该返回[(a*b, y*y) | ...y 您的代码是您描述的“c”。
  • 指定的重复项回答了不同的问题。这个问题是具体的,一个是一般性的。

标签: performance list haskell list-comprehension


【解决方案1】:

因此,无限列表上的嵌套列表推导当然不会终止。

幸运的是,您的列表不是无限的。有个限度。如果x = a*b &lt; 500,那么我们知道一定是a &lt; 500b &lt; 500。此外,c = y*y &lt; 1001 只是 y &lt; 32。所以,

listPairs :: [(Int, Int)] 
listPairs = 
    [(x, c*c) | c <- [1..31], a <- [1..499],    -- a*b < 500 ==> b<500/a ,
                b <- [a..min 499 (div 500 a)],  -- a*b==b*a  ==> b >= a
                let x = a*b, x > 5,  
                -- (a*b) < 500, (c*c) < 1001,   -- no need to test this
                rem (c*c) x == 0]    

mod 0 n == 0 微不足道,所以我在这里从“自然数”中排除 0。

尽管我们在x=a*b 中将b 的值限制为b &gt;= a,但这里仍然会产生一些重复,因为x 可以有多种表示形式(例如1*6 == 2*3)。

您可以使用Data.List.nub 摆脱它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-06
    • 2012-08-30
    • 2012-06-02
    • 2022-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多