Números de Haskell Hamming, funciona pero muestra duplicados

Estoy tratando de generar números de hamming en haskell, el problema es que obtengo números duplicados en mi lista de salida y no puedo entender por qué exactamente. ¿Debo simplemente crear una función de eliminación de duplicados o simplemente me estoy perdiendo algo simple?

También en la función hamming me gustaría asegurarme de que el tamaño de la lista de entrada sea exactamente 3, ¿cómo encuentro el tamaño de una lista para poder hacer la comparación?

{- 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" -}

preguntado el 27 de julio de 12 a las 20:07

casualmente, nodups xs = map head (Data.List.group xs) para listas ordenadas no decrecientes. -

2 Respuestas

Obtiene duplicados porque muchos de los números de hamming son múltiplos de varios de los números base, y no elimina los duplicados en su merge función. Por ejemplo, para el clásico 2, 3, 5 Números de Hamming, obtienes 6 como 2 * 3 al igual que 3 * 2.

Por supuesto, podría crear una función de eliminación de duplicados. Dado que la lista que crea está ordenada, eso ni siquiera sería muy ineficiente. O podría eliminar los duplicados en la función de combinación.

¿Cómo encuentro el tamaño de una lista para poder hacer la comparación?

Puede obtener la longitud de una lista usando el length función que está disponible desde el Prelude, pero déjame advertirte ahora mismo que llamar length sólo debe hacerse si la longitud es realmente necesaria, ya que length tiene que recorrer toda la lista para calcular su longitud. Si la lista es larga, lleva mucho tiempo y puede causar un gran uso de memoria si se hace referencia a la lista en otro lugar para que no se pueda recolectar basura. Si la lista es incluso infinita, la evaluación de su longitud, por supuesto, nunca terminará.

Lo que quieres hacer también se puede lograr mediante la combinación de patrones,

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

También puede utilizar un protector con un length comprobar

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

para asegurarse de que su lista de entrada tenga exactamente tres elementos, pero se arrepentirá si llama hamming 10 [1 .. ].

Respondido 27 Jul 12, 20:07

En la pestaña List módulo, Haskell tiene un eliminador de duplicados llamado nub. Aquí está en hoogle: http://www.haskell.org/hoogle/?hoogle=nub. Sin embargo, esto es O (n ^ 2), por lo que es mejor que cambie merge. Pero puede valer la pena usar primero una solución lenta ya escrita para usted, antes de optimizar.

Sospecho que está tratando de aprender Haskell con este pequeño ejercicio, pero aquí hay otra forma de escribir los números de Hamming (sin duplicados, pero no en orden) usando la mónada Lista:

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

Esto hace una lista perezosa e infinita de números de Hamming. De manera equivalente, puede escribir esto usando un lista de comprensión:

uglyNumbers' = [(2^(n-k-j))*(3^j)*(5^k) | n <- [0..], k <- [0..n], j <- [0..n-k]] 

Respondido 28 Jul 12, 17:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.