2010-10-14 21 views
17

non riesce a capire come unire due liste nel seguente modo in Haskell:Unire due liste in Haskell

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

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

Di solito si impara di più se si spiega che cosa si è tentato e perché non ha funzionato, che la gente modo può fare un po 'di riempimento-in-the- lacune invece di darti una porzione di codice. –

+0

Correlati: [Elenco interleave di elenchi in Haskell] (http://stackoverflow.com/q/14186433/2157640) – Palec

risposta

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

Sono nuovo alla programmazione funzionale, e il codice mi fa meravigliare questo: l'ottimizzazione chiamata coda si applica in quel anche la forma della ricorsione? –

+1

No, non è così. La coda è chiamata (:) e non ha bisogno di ottimizzazione. – Ingo

+0

C'è una versione più laziale di questo in [un'altra risposta] (http://stackoverflow.com/a/3987188/2157640). È pigro nel secondo parametro. – Palec

6

EDIT: Date un'occhiata a risposta e commenti di Ed'ka !

Altra possibilità:

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

O, se vi piace applicativo:

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

Sì, a cattivo, che funziona solo su elenchi di lunghezza uguale. – bogatyrjov

21

Allora perché pensi così semplice (. Concat trasposizione) "non è abbastanza carina"? Presumo che hai provato qualcosa di simile:

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

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

questo modo si può evitare la ricorsione esplicita (vs la prima risposta) e ancora è più semplice rispetto alla seconda risposta. Quindi quali sono gli svantaggi?

+0

Ah, ho dimenticato la trasposizione e ho perso il commento. Molto bello, +1 (ma non direi necessariamente che è molto più semplice della mia prima soluzione.) – danlei

+3

Accetto. La tua soluzione è probabilmente ancora più semplice. Il vero problema però è che non è corretto al 100%: per gli elenchi di lunghezze diverse (come nell'input del campione dalla domanda) non funziona come previsto (tailing '5' manca). –

+0

Buona cattura! Ho trascurato il 5 nell'output di esempio. Aggiornerò la mia risposta con un puntatore alla tua risposta e ai tuoi commenti. Grazie! – danlei

50

vi voglio proporre una versione più pigri di unione:

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

Per un caso di esempio, l'utilizzo è possibile controllare una recente domanda SO su lazy generation of combinations.
La versione nella risposta accettata è inutilmente severa nel secondo argomento ed è ciò che è migliorato qui.

+0

Bene, questo mette tutti gli elementi di ys alla fine, quindi non funziona. Ma penso che volevi invertire l'ordine delle prime due equazioni nella soluzione di andri. – Yitz

+13

No, fa la stessa cosa - si alterna tra ciascuna lista. Si noti che 'xs' e' ys' sono scambiati nella chiamata ricorsiva. –

+1

È un'ottima soluzione! Vorrei poter pensare a qualcosa del genere io stesso – 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

Questa soluzione non è corretta. La riga finale dovrebbe essere 'pp (h: t) (a: b) = h: a: pp t b'. – bisserlis

4

Sicuramente un caso per un unfold:

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

Il tuo codice originale non ha funzionato; 'interleave [] [1,2,3]' darebbe '[]'. Penso che dovrebbe funzionare ora. – dfeuer

+0

un altro caso per il tuo ['unfoldr''] (http://stackoverflow.com/q/24519530/849891) apomorfismo! (quindi sarà equivalente a [questa risposta] (http://stackoverflow.com/a/3987188/849891) sopra). –

+0

@dfeuer (il commento sopra) –