[英]How to divide every element in a list with each element in another list in haskell
Suppose I have an infinite list A = [1..]
I want to divide each element in A
with all elements in list B = [1..10]
If any element in list A
is divisible by all the elements in B
I need to print it. 假设我有一个无限列表
A = [1..]
我想将A
每个元素除以列表B = [1..10]
所有元素B = [1..10]
如果列表A
任何元素都可以被B
所有元素整除,我需要打印。 I need to continue this till I get 10 such numbers. 我需要继续进行直到得到10个这样的数字。
The following attempt did not work: 以下尝试不起作用:
print(minimum([x | x <- [1..], y <- [1..10], rem x y == 0]))
You wrote: 你写了:
print(minimum([x | x <- [1..], y <- [1..10], rem x y == 0]))
Now this will not work for several reasons: 现在,由于以下几个原因,这将无法正常工作:
x
to the list in the list comprehension, given there is any element y
in [1..10]
that divides x
. x
给出有任何元素到列表中列表解析, y
在[1..10]
其将x
。 Furthermore for any such y
, we will add x
one time. y
,我们将x
加一次。 So given x
is 6
, it will add it three four times, since 6
is dividable by 1, 2, 3 and 6; x
为6
,它将乘以三四次,因为6
可以被1、2、3和6分开; head
; head
理解第一个要素; minimum
will only produce one element, but you want the first 10. minimum
只会产生一个元素,但是您想要第一个10。 First we can use list comprehension to generate all these numbers (for arbitrary lists as
and bs
): 首先,我们可以使用列表推导生成所有这些数字(对于
as
和bs
任意列表):
divide_all as bs = [a | a <- as, all ((0 ==) . mod a) bs]
So here the list comprehension iterates over as
and assigns every element to a
. 所以这里的列表理解遍历
as
环节都分配给a
。 Next we have a filter all ((0 ==) . mod a) bs
, which is a compact form of all (\\b -> mod ab == 0) bs
. 接下来我们有一个过滤器
all ((0 ==) . mod a) bs
,这是all (\\b -> mod ab == 0) bs
的紧凑形式。 So it checks whether for all members b
in bs
, mod ab == 0
(so a
is dividable by b
). 因此,它检查
bs
所有成员b
是否为mod ab == 0
(因此a
可被b
整除)。 If the filter is satisfied, then we add a
(in the head of the list comprehension) to the result. 如果满足过滤条件,则在结果中添加
a
(在列表理解的开头)。 Note that such lists are build lazily, so the fact that as
has an infinite number of elements, is not a problem. 请注意,这样的列表是延迟构建的,因此
as
具有无限数量的元素这一事实不是问题。
Now we can use take :: Int -> [a] -> [a]
to take the first 10 of these numbers, and thus print these: 现在我们可以使用
take :: Int -> [a] -> [a]
来获取这些数字的前10个,并打印出:
mapM_ print (take 10 $ divide_all [1..] [1..10])
which prints: 打印:
Prelude> mapM_ print (take 10 $ divide_all [1..] [1..10])
2520
5040
7560
10080
12600
15120
17640
20160
22680
25200
The above approach is not very efficient: for every element of a
, we need to check whether it is dividable with every element of b
. 上述方法是不是很有效:对的每一个元素
a
,我们需要检查它是否是可分的与每一个元素b
。 It took my machine 2.16 seconds to calculate the 1000th element of this list, and 10.21 seconds to find the 5000th element. 我的机器花了2.16秒来计算此列表的第1000个元素,花了10.21秒才找到了第5000个元素。
We can speed up the last one, by calculating the least common multiple (lcm) of all the elements in b
, and check if a number is dividable by the lcm: 我们可以通过计算
b
中所有元素的最小公倍数(lcm)来加快最后一个的速度,并检查数字是否可被lcm整除:
divide_all as bs = [a | a <- as, mod a lcmb == 0] -- optimized version
where lcmb = foldr1 lcm bs
So now we have to perform only one check. 所以现在我们只需要执行一项检查。 Calculating the 1000th element now takes 0.95 seconds, and calculating the 5000th element, takes 4.54 seconds.
现在计算第1000个元素需要0.95秒,而计算第5000个元素需要4.54秒。
as = [1..]
as = [1..]
In case as
is known to be [1..]
we can boost this code dramatically, since we know that the elements of a
are all multiples of lcmb
. 如果
as
是已知的[1..]
我们可以显着提升该代码,因为我们知道的元素a
是所有的倍数lcmb
。 So we can drop the as
parameter, and use: 因此,我们可以删除
as
参数,并使用:
divide_all bs = [lcmb*a | a <- [1..]] -- optimized version
where lcmb = foldr1 lcm bs
Now calculating the 1000th element takes 0.01 seconds, and calculating the 5000th element 0.03 seconds. 现在计算第1000个元素需要0.01秒,计算第5000个元素需要0.03秒。 But of course this only works given the assumption.
但是当然,这仅在给定假设的情况下有效。
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.