2010-10-14 4 views
17

ne peux pas comprendre comment fusionner deux listes de la manière suivante dans Haskell:La fusion de deux listes dans Haskell

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

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

Habituellement vous en savoir plus si vous expliquez ce que vous avez essayé et pourquoi il ne fonctionne pas, que les gens de façon peut faire un peu de remplissage in-the lacunes au lieu de simplement vous donner un morceau de code. –

+0

Connexe: [Interleave liste des listes dans Haskell] (http://stackoverflow.com/q/14186433/2157640) – Palec

Répondre

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

Je suis nouveau à la programmation fonctionnelle, et le code me fait me demander ceci: Est-ce que l'optimisation de l'appel de queue s'applique dans ce forme de récursivité aussi? –

+1

Non, ce n'est pas le cas. L'appel de queue est (:), et il n'a pas besoin d'optimisation. – Ingo

+0

Il existe une version plus paresseuse de ceci dans [une autre réponse] (http://stackoverflow.com/a/3987188/2157640). C'est paresseux dans le second paramètre. – Palec

6

EDIT: Jetez un oeil à la réponse et les commentaires de Ed'ka !

Une autre possibilité:

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

Ou, si vous aimez Applicative:

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

Oui, à mauvais, cela ne fonctionne que sur des listes de longueur égale. – bogatyrjov

21

Alors, pourquoi pensez-vous que simple (. Concat transposent) "est pas assez jolie"? Je suppose que vous avez essayé quelque chose comme:

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

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

Ainsi vous pouvez éviter la récursivité explicite (vs la première réponse) et encore il est plus simple que la deuxième réponse. Alors, quels sont les inconvénients?

+0

Ah, j'ai oublié de transposer, et raté le commentaire. Très bien, +1 (Mais je ne dirais pas forcément que c'est beaucoup plus facile que ma première solution.) – danlei

+3

D'accord. Votre solution est probablement encore plus simple. Le vrai problème est que ce n'est pas 100% correct: pour les listes de différentes longueurs (comme dans l'exemple de saisie de la question) cela ne fonctionne pas comme prévu (tailing '5' est manquant). –

+0

Bonne prise! J'ai négligé le 5 dans la sortie de l'échantillon. Je mettrai à jour ma réponse avec un pointeur vers votre réponse et vos commentaires. Merci! – danlei

50

Je veux proposer une version de fusion paresseuses:

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

Pour un exemple de cas d'utilisation, vous pouvez vérifier une récente question au sujet de SO lazy generation of combinations.
La version dans la réponse acceptée est inutilement stricte dans le second argument et c'est ce qui est amélioré ici.

+0

Eh bien, cela met tous les éléments de ys à la fin, donc ça ne marche pas. Mais je pense que vous vouliez dire inverser l'ordre des deux premières équations dans la solution d'Andri. – Yitz

+13

Non, il fait la même chose - alterne entre chaque liste. Notez que 'xs' et' ys' sont permutés dans l'appel récursif. –

+1

C'est une excellente solution! Je souhaite que je pourrais penser à quelque chose comme moi-même – 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

Cette solution est incorrecte. La dernière ligne devrait être 'pp (h: t) (a: b) = h: a: pp t b'. – bisserlis

4

Sûrement un cas pour un dépliage:

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

Votre code original n'a pas fonctionné. 'entrelace [] [1,2,3]' donnerait '[]'. Je pense que cela devrait fonctionner maintenant. – dfeuer

+0

un autre cas pour votre ['unfoldr''] (http://stackoverflow.com/q/24519530/849891) apomorphisme! (alors ce sera équivalent à [cette réponse] (http://stackoverflow.com/a/3987188/849891) ci-dessus). –

+0

@dfeuer (le commentaire ci-dessus) –