Home > Enterprise >  Merging the elements of two nested lists with Haskell
Merging the elements of two nested lists with Haskell

Time:09-17

I want to append lists in one list and lists in a second list.

Using concat creates one list of all elements, while zip seems to combine the two nested lists into a single nested list without combining the child lists.

let x = [["one", "two"],["five", "six"], ["nine", "ten"]] 

let y = [["three", "four"],["seven", "eight"], ["eleven", "twelve"]]

Should become

[["one", "two", "three", "four"], ["five", "six", "seven", "eight"], ["nine", "ten", "eleven", "twelve"]]

How do I achieve the above result? My hunch is to use map though I have been unsuccessful.

CodePudding user response:

In some languages like Scheme map can accept any number of lists, but in Haskell, the binary map has its own name, zipWith:

zipWith (  ) x y

will do what you wanted.

How to get there, playing at the REPL:

> zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]
-- BTW these are not lists, but tuples

> zipWith (,) x y                    -- same thing as zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]

> zipWith (\a b -> (a,b)) x y        -- same thing as the above
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]

> zipWith (\a b -> [a,b]) x y        -- not the same thing as the above
[[["one","two"],["three","four"]],[["five","six"],["seven","eight"]],[["nine","ten"],["eleven","twelve"]]]

> zipWith (\a b -> concat [a,b]) x y    -- success!
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]

> zipWith (\a b -> a    b) x y       -- equivalent to the above
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]

> zipWith (  ) x y                   -- finally, simplified.
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]

But you could also have used map as you wanted, to process the output of zip:

> zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]

> map id $ zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]

> map (\(a,b) -> a    b) $ zip x y   -- the same as zipWith (  )
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]

Another way of achieving this is by using transpose which is kind of a zip itself:

map concat $ transpose [x,y]

This uses the same concat we saw above with two lists, which will now work on any number of sublists taken together in a single list, each from the originals (here, still two):

> transpose [x,y]
[[["one","two"],["three","four"]],[["five","six"],["seven","eight"]],[["nine","ten"],["eleven","twelve"]]]

Thus it is effortlessly extendable to processing any number of lists:

map concat $ transpose [x,y,z]

etc.

  • Related