我正在尝试在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" -}
答案 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]]