Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to zip lists with different length?

Tags:

haskell

How can I zip two lists like

["Line1","Line2","Line3"]
["Line4","Line5"]

without discarding rest elements in first list?

I'd like to zip extra elements with empty list, if it can be done.

like image 483
zerospiel Avatar asked Mar 14 '14 10:03

zerospiel


3 Answers

zipWithPadding :: a -> b -> [a] -> [b] -> [(a,b)]
zipWithPadding a b (x:xs) (y:ys) = (x,y) : zipWithPadding a b xs ys
zipWithPadding a _ []     ys     = zip (repeat a) ys
zipWithPadding _ b xs     []     = zip xs (repeat b)

As long as there are elements, we can simply zip them. As soon as we run out of elements, we simply zip the remaining list with an infinite list of the padding element.

In your case, you would use this as

zipWithPadding "" "" ["Line1","Line2","Line3"] ["Line4","Line5"]
-- result: [("Line1","Line4"),("Line2","Line5"),("Line3","")]
like image 173
Zeta Avatar answered Oct 31 '22 21:10

Zeta


Another solution is to make a zip function that works on monoids and fills in the missing values with mempty:

import Data.Monoid

mzip :: (Monoid a, Monoid b) => [a] -> [b] -> [(a, b)]
mzip (a:as) (b:bs) = (a, b) : mzip as bs
mzip []     (b:bs) = (mempty, b) : mzip [] bs
mzip (a:as) []     = (a, mempty) : mzip as []
mzip _      _      = []

> mzip ["Line1","Line2","Line3"] ["Line4","Line5"]
[("Line1","Line4"),("Line2","Line5"),("Line3","")]
like image 35
Reite Avatar answered Oct 31 '22 22:10

Reite


An alternative implementation of Reite's solution, using higher order functions, just for fun. :) Possibly slower, though, since I guess the length functions will require additional traversals of the lists.

import Data.Monoid (mempty)

zipPad :: (Monoid a, Monoid b) => [a] -> [b] -> [(a,b)]
zipPad xs ys = take maxLength $ zip (pad xs) (pad ys)
    where
        maxLength = max (length xs) (length ys)
        pad v = v ++ repeat mempty
like image 1
imladris Avatar answered Oct 31 '22 22:10

imladris