在Haskell中列出除数列表

时间:2009-09-26 06:18:14

标签: haskell math

我在eulerproject中正在做问题21。 一部分需要找到一个数字的适当除数列表。即剩余的n和一些小于n的地方。所以我做了这个Haskell,但是GHCI对我很生气。

divisors n =[ n | n <- [1..(n-1)], n `rem` [1..(n-1)] ==0 ]

问题在于我不知道如何制作:

n `rem` [1..(n-1)]

这样它只返回小于n的数字,该数字均匀分配到n

2 个答案:

答案 0 :(得分:18)

你只需要一个单独的变量。

Prelude> let divisors n = [x | x <- [1..(n-1)], n `rem` x == 0]
Prelude> divisors 20
[1,2,4,5,10]
Prelude> divisors 30
[1,2,3,5,6,10,15]

现在,如果你想提高效率,我们已经知道除数不会超过n的一半,我们知道1是一切的除数。而且,让我们继续,让它更多的Haskell-y启动,避免列表理解:

Prelude> let divisors n = 1 : filter ((==0) . rem n) [2 .. n `div` 2]
Prelude> divisors 20
[1,2,4,5,10]
Prelude> divisors 30
[1,2,3,5,6,10,15]
Prelude> divisors 31
[1]

答案 1 :(得分:6)

如果除数列表的顺序不重要,只需检查[2..sqrt n]范围内的除数,就可以显着提高效率。

这样的事情(如果你想的更多,你可能会做一些局部优化):

divisors' n = (1:) $ nub $ concat [ [x, div n x] | x <- [2..limit], rem n x == 0 ]
     where limit = (floor.sqrt.fromIntegral) n

除数是先前的实现,除数是新的:

*Main> (sum.divisors) 10000000
14902280
(4.24 secs, 521136312 bytes)

*Main> (sum.divisors') 10000000
14902280
(0.02 secs, 1625620 bytes)

注意: 我使用nub去除任何重复,实际上唯一可能的重复是限制,如果n是平方数。通过更好地处理这种情况,你可以使它更有效率,但我发现这种方式更具可读性(如果运行时间不重要)。