假设我有一个无限列表A = [1..]
我想每个元素在A
在列表B = [1..10]
所有元素划分如果在列表A
任何元素除尽所有B
中的元素需要打印。 我需要继续这个,直到我得到10个这样的数字。如何的每一个元素与另一个列表中的每个元素在Haskell划分在一个列表
下尝试没有工作:
print(minimum([x | x <- [1..], y <- [1..10], rem x y == 0]))
假设我有一个无限列表A = [1..]
我想每个元素在A
在列表B = [1..10]
所有元素划分如果在列表A
任何元素除尽所有B
中的元素需要打印。 我需要继续这个,直到我得到10个这样的数字。如何的每一个元素与另一个列表中的每个元素在Haskell划分在一个列表
下尝试没有工作:
print(minimum([x | x <- [1..], y <- [1..10], rem x y == 0]))
您写道:
print(minimum([x | x <- [1..], y <- [1..10], rem x y == 0]))
现在,这不会有以下几个原因工作:
x
添加到列表理解列表中,因为有任何元素y
在[1..10]
中除以x
。此外,对于任何此类y
,我们将一次添加x
。所以给定x
是6
,它会将它添加三次四次,因为6
可以被1,2,3和6除尽;head
;minimum
只会产生一个元素,但你要第10首先,我们可以使用列表解析生成所有这些数字(任意名单as
和bs
):
divide_all as bs = [a | a <- as, all ((0 ==) . mod a) bs]
所以这里的名单理解迭代as
环节都分配给a
。接下来我们有一个过滤器all ((0 ==) . mod a) bs
,这是一个紧凑的形式all (\b -> mod a b == 0) bs
。因此它检查是否b
中的所有成员bs
,mod a b == 0
(因此a
可由b
分割)。如果过滤器得到满足,则我们将a
(在列表理解的头部)添加到结果中。请注意,这样的列表是懒散地构建的,因此as
具有无限数量的元素的事实不是问题。
现在我们可以使用take :: Int -> [a] -> [a]
采取这些数字的第一个10,从而打印这些:
mapM_ print (take 10 $ divide_all [1..] [1..10])
它打印:
Prelude> mapM_ print (take 10 $ divide_all [1..] [1..10])
2520
5040
7560
10080
12600
15120
17640
20160
22680
25200
上述方法效率不高:对于a
的每个元素,我们需要检查它是否可以用b
的每个元素进行分割。我的机器用了2.16秒来计算这个列表的第1000个元素,用了10.21秒找到第5000个元素。
可加快我们的最后一个,通过计算最小公倍数(LCM)的b
所有的元素,并检查是否一个数是由LCM可分:所以现在
divide_all as bs = [a | a <- as, mod a lcmb == 0] -- optimized version
where lcmb = foldr1 lcm bs
我们只需要执行一次支票。现在计算第1000个元素需要0.95秒,计算第5000个元素需要4.54秒。
as = [1..]
如果as
被称为是[1..]
我们可以显着提升该代码,因为我们知道,a
的元素是lcmb
倍数。因此,我们可以放下as
参数,并使用:
divide_all bs = [lcmb*a | a <- [1..]] -- optimized version
where lcmb = foldr1 lcm bs
现在计算的第1000个元素需要0.01秒,并计算第5000元0.03秒。但当然这只有在假设的情况下才有效。
@ Willem Van Onsem谢谢您的详细解释:) – VVV
let divcheck = (take 10 .) . filter . flip (all . ((0 ==) .) . mod)
divcheck [1..10] [1..]
-- [2520,5040,7560,10080,12600,15120,17640,20160,22680,25200]
divcheck [1,2,3] [1..]
-- [6,12,18,24,30,36,42,48,54,60]
你有什么试过自己? –
@ Willem Van Onsem我写了一个绝对不会给出正确答案的代码! print(minimum([x | x < - [1 ..],y < - [1..10],rem x y == 0])) – VVV