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.