在k-composite数的Haskell中创建无限列表

时间:2017-09-26 05:55:33

标签: list function haskell

k-复合数是一个复合数,其中k个因子不包括1和它自身。我试图编写将采用整数k的代码并返回所有k-composite的无限列表。所以使用take 5 $ kcomposite 2将返回[6,8,10,14,15]。我写了两个函数来完成这个:

factors :: Int -> [Int]
factors n = [x | x <- [1..n], n `mod` x == 0]

kcomposite ::  Int -> [Int]
kcomposite n = [x | x <- [1..], (length (factors n)) == (x-2)]

我编译没有问题,但是当我尝试运行它们时,ghci永远不会停止运行。这是有道理的,因为无限列表,但即使我只尝试获取列表中的前几个元素,就像在上面的例子中一样。我无法理解我做错了什么。

2 个答案:

答案 0 :(得分:5)

  

k-复合数是一个复合数,其中k个因子不包括1和它本身

由于您的factors函数会返回数字的所有因子(包括1及其本身),因此该数字将大于提供的k。这就是为什么您需要与k + 2而不是k - 2进行比较

的原因

此外,当k小于0时,您仍然会让程序永远不会停止运行,这就是您可能想要处理此边缘情况的原因。

factors :: Int -> [Int]
factors n = [x | x <- [1..n], n `mod` x == 0]

kcomposite ::  Int -> [Int]
kcomposite k
  | k < 0 = []
  | otherwise = [x | x <- [1..], length (factors x) == (k + 2)]

答案 1 :(得分:2)

这是我对此任务略有不同的方法,效率更高。

提升键是一直检查到最后但仅限于平方根。我的意思是,如果我们想找到100的复合材料,我们不需要控制所有100个数字。我们只需要控制sqrt 100(例如[2..10])即可查看(mod 100 x) == 0。我们从2开始,因为你不想要1和数字本身。一旦我们得到令人满意的数字100 div x应该给我们另一个。因此,如果2是复合,则100 div 2(50)是另一个,如4收益25和5收益20.当然,当我们到10时,它将给我们另外10,我们将只评估其中一个。酷..!

所以这是代码

kcomposites :: Int -> [Int]
kcomposites k = 
  let factors n = concat [bool [x, n `div` x] [x] (x^2 == n) 
                          | x <- [2..limit], n `mod` x == 0]
          where limit = truncate . sqrt . realToFrac $ n
  in foldr (\n rs -> bool rs (n:rs) (k == (length . factors $ n))) [] [2..]

以下是前5个元素的k = 19的代码性能;

*Main> take 5 . kcomposites $ 19
[576,1600,2916,3136,7744]
(0.43 secs, 174,826,272 bytes)

以下是前5个元素的k = 19的代码性能;

*Main> take 5 . kcomposite $ 19
[576,1600,2916,3136,7744]
(17.61 secs, 6,246,022,504 bytes)

注意:我不建议检查5个元素的k = 5。即使这段代码需要15分钟才能得出[64,729,15625,117649,1771561]上述代码可能需要花费大量时间(比如一天或更长时间)。

可以将它们与take 3进行比较。

*Main> take 3 . kcomposites $ 5
[64,729,15625]
(1.14 secs, 472,228,880 bytes)

*Main> take 3 . kcomposite $ 5
[64,729,15625]
(69.84 secs, 25,409,801,688 bytes)