2010-10-14 30 views
17

No se puede encontrar la manera de fusionar dos listas de la siguiente manera en Haskell:La fusión de dos listas en Haskell

INPUT: [1,2,3,4,5] [11,12,13,14] 

OUTPUT: [1,11,2,12,3,13,4,14,5] 
+6

Por lo general, a aprender más si se le explica lo que ha intentado y por qué no funcionó, de esa manera la gente puede hacer algo de relleno-en-el brechas en lugar de solo darte un pedazo de código. –

+0

Relacionados: [Lista de listas de intercalación en Haskell] (http://stackoverflow.com/q/14186433/2157640) – Palec

Respuesta

39
merge :: [a] -> [a] -> [a] 
merge xs  []  = xs 
merge []  ys  = ys 
merge (x:xs) (y:ys) = x : y : merge xs ys 
+0

Soy nuevo en la programación funcional, y el código me hace preguntarme esto: ¿se aplica la optimización de la cola de llamadas en ese forma de recursión también? –

+1

No, no es así. La llamada final es (:), y no necesita optimización. – Ingo

+0

Hay una versión más lenta de esto en [otra respuesta] (http://stackoverflow.com/a/3987188/2157640). Es flojo en el segundo parámetro. – Palec

6

EDIT: Tome un vistazo a los comentarios de respuesta y Ed'ka !

Otra posibilidad:

merge xs ys = concatMap (\(x,y) -> [x,y]) (zip xs ys) 

O, si te gusta Aplicativo:

merge xs ys = concat $ getZipList $ (\x y -> [x,y]) <$> ZipList xs <*> ZipList ys 
+3

Sí, mal, eso solo funciona en listas de igual longitud. – bogatyrjov

21

Entonces, ¿por qué cree que sencilla (. Concat transponer) "no es lo suficientemente bonita"? Asumo que has probado algo como:

merge :: [[a]] -> [a] 
merge = concat . transpose 

merge2 :: [a] -> [a] -> [a] 
merge2 l r = merge [l,r] 

De este modo se puede evitar una recursión explícita (vs la primera respuesta) y todavía es más simple que la segunda respuesta. ¿Cuáles son los inconvenientes?

+0

Ah, me olvidé de la transposición, y me perdí el comentario. Muy bien, +1 (Pero no necesariamente diría que es mucho más fácil que mi primera solución.) – danlei

+3

De acuerdo. Su solución probablemente sea aún más sencilla. Sin embargo, el verdadero problema es que no es 100% correcta: para las listas de diferentes longitudes (como en la entrada de muestra de la pregunta) no funciona como se esperaba (seguimiento '5' falta). –

+0

¡Buena captura! Pasé por alto el 5 en la salida de muestra. Actualizaré mi respuesta con un puntero a su respuesta y comentarios. ¡Gracias! – danlei

50

quiero proponer una versión más perezoso de fusión:

merge [] ys = ys 
merge (x:xs) ys = x:merge ys xs 

Para un caso de ejemplo, el uso se puede comprobar una reciente Así que la pregunta acerca lazy generation of combinations.
La versión en la respuesta aceptada es innecesariamente estricta en el segundo argumento y eso es lo que se mejora aquí.

+0

Bueno, eso pone todos los elementos de ys al final, por lo que no funciona. Pero creo que lo que querías decir es invertir el orden de las dos primeras ecuaciones en la solución de andri. – Yitz

+13

No, hace lo mismo: alterna entre cada lista. Observe que 'xs' y' ys' se intercambian en la llamada recursiva. –

+1

¡Es una gran solución! Ojalá pudiera pensar en algo así yo mismo – bogatyrjov

-2
-- ++ 
pp [] [] = [] 
pp [] (h:t) = h:pp [] t 
pp (h:t) [] = h:pp t [] 
pp (h:t) (a:b) = h : pp t (a:b) 
+1

Esta solución es incorrecta. La línea final debe ser 'pp (h: t) (a: b) = h: a: pp t b'. – bisserlis

4

Sin duda, un caso para un Despliegue:

interleave :: [a] -> [a] -> [a] 
interleave = curry $ unfoldr g 
    where 
    g ([], []) = Nothing 
    g ([], (y:ys)) = Just (y, (ys, [])) 
    g (x:xs, ys) = Just (x, (ys, xs)) 
+0

Tu código original no funcionó; 'interleave [] [1,2,3]' daría '[]'. Creo que debería funcionar ahora. – dfeuer

+0

otro caso para su apomorfismo ['unfoldr''] (http://stackoverflow.com/q/24519530/849891)! (Entonces será equivalente a [esta respuesta] (http://stackoverflow.com/a/3987188/849891) arriba). –

+0

@dfeuer (el comentario anterior) –