Haskell Hamming数字,有效,但显示重复

时间:2012-07-27 19:25:18

标签: haskell hamming-numbers smooth-numbers

我正在尝试在haskell中生成汉明数字,问题是我在输出列表中得到了重复的#并且我无法弄清楚为什么。我应该只创建一个删除重复项功能,还是我只是遗漏了一些简单的东西?

另外在汉明函数中我想确保输入列表的大小正好是3,我如何找到列表的大小以便进行比较?

{- Merge lists x&y of possibly infinite lengths -}
merge [] [] = []
merge [] ys = ys
merge xs [] = xs
merge xs ys = min x y : if x < y then merge (tail xs) ys
                             else merge xs (tail ys)
    where x = head xs
          y = head ys

{- multiply each element in y by x -}
times x [] = []
times x y = x * (head y) : times x (tail y)

{- find the hamming numbers of the input primes list -}
ham [] = []
ham x = 1 : merge (times (head x) (ham x))
             (merge (times (x !! 1) (ham x)) (times (last x) (ham x)))

{- returns x hamming #'s based on y primes of size 3 -}
hamming x [] = []
hamming x y = take x (ham y) 
{- hamming x y = if "y.size = 3" then take x (ham y) 
                                 else "Must supply 3 primes in input list" -}

2 个答案:

答案 0 :(得分:2)

你得到重复,因为许多汉明数字是几个基数的倍数,你不会删除merge函数中的重复项。例如,对于经典的2, 3, 5汉明数字,您获得6 2 * 3以及3 * 2

您当然可以创建重复删除功能。由于您创建的列表已排序,因此效率甚至不高。或者您可以删除合并功能中的重复项。

  

如何找到列表的大小以便进行比较?

您可以使用length中提供的Prelude函数获取列表的长度,但现在让我警告您,只有在调用length时才应该这样做长度确实是必需的,因为length必须遍历整个列表来计算其长度。如果列表很长,则需要花费大量时间,并且如果列表在别处被引用,则可能导致大量内存使用,从而无法对其进行垃圾回收。如果列表甚至是无限的,那么评估它的长度当然永远不会终止。

你想做的事情也可以通过模式匹配来实现,

ham [a, b, c] = list
  where
    list = 1 : merge (map (a*) list) (merge (map (b*) list) (map (c*) list))
ham _ = []

您还可以使用length支票

的警卫
hamming x y
    | length y == 3 = take x (ham y)
    | otherwise     = []

确保您的输入列表中只有三个元素,但如果您致电hamming 10 [1 .. ],您会后悔。

答案 1 :(得分:1)

List模块中,Haskell有一个名为nub的重复删除程序。这是在hoogle:http://www.haskell.org/hoogle/?hoogle=nub。这是O(n ^ 2),所以你最好改变merge。但在优化之前,首先使用已为您编写的慢速解决方案可能是值得的。

我怀疑你正在尝试通过这个小练习来学习Haskell,但是这是另一种使用 List monad 写出汉明数字(没有重复但不按顺序)的方法:

uglyNumbers = do { n <- [0..] 
                 ; k <- [0..n] 
                 ; j <- [0..n-k] 
                 ; return $ (2^(n-k-j))*(3^j)*(5^k) }

这是一个懒惰,无限的汉明数字列表。您可以使用 list comprehension

等效地编写它
uglyNumbers' = [(2^(n-k-j))*(3^j)*(5^k) | n <- [0..], k <- [0..n], j <- [0..n-k]]