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. I need to continue this till I get 10 such numbers.
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
. Furthermore for any such y
, we will add x
one time. So given x
is 6
, it will add it three four times, since 6
is dividable by 1, 2, 3 and 6; head
; minimum
will only produce one element, but you want the first 10. First we can use list comprehension to generate all these numbers (for arbitrary lists as
and 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
. Next we have a filter all ((0 ==) . mod a) bs
, which is a compact form of 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
). If the filter is satisfied, then we add a
(in the head of the list comprehension) to the result. Note that such lists are build lazily, so the fact that as
has an infinite number of elements, is not a problem.
Now we can use take :: Int -> [a] -> [a]
to take the first 10 of these numbers, and thus print these:
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
. It took my machine 2.16 seconds to calculate the 1000th element of this list, and 10.21 seconds to find the 5000th element.
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:
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.
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
. So we can drop the as
parameter, and use:
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. 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]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.