[英]How to divide every element in a list with each element in another list in haskell
假设我有一个无限列表A = [1..]
我想将A
每个元素除以列表B = [1..10]
所有元素B = [1..10]
如果列表A
任何元素都可以被B
所有元素整除,我需要打印。 我需要继续进行直到得到10个这样的数字。
以下尝试不起作用:
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 ab == 0) bs
的紧凑形式。 因此,它检查bs
所有成员b
是否为mod ab == 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个元素。
我们可以通过计算b
中所有元素的最小公倍数(lcm)来加快最后一个的速度,并检查数字是否可被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秒。 但是当然,这仅在给定假设的情况下有效。
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]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.