Zip with default value instead of dropping values?

后端 未结 9 834
夕颜
夕颜 2020-12-01 18:30

I\'m looking for a function in haskell to zip two lists that may vary in length.
All zip functions I could find just drop all values of a lists that is longer than the o

9条回答
  •  不知归路
    2020-12-01 19:08

    No length, no counting, no hand-crafted recursions, no cooperating folds. transpose does the trick:

    zipLongest :: a -> b -> [a] -> [b] -> [(a,b)]
    zipLongest x y xs ys = map head . transpose $   -- longest length;
                    [                                 --   view from above:
                      zip  xs 
                          (ys ++ repeat y)            -- with length of xs
                    , zip (xs ++ repeat x) 
                           ys                         -- with length of ys
                    ]
    

    The result of transpose is as long a list as the longest one in its input list of lists. map head takes the first element in each "column", which is the pair we need, whichever the longest list was.


    (update:) For an arbitrary number of lists, efficient padding to the maximal length -- aiming to avoid the potentially quadratic behaviour of other sequentially-combining approaches -- can follow the same idea:

    padAll :: a -> [[a]] -> [[a]]
    padAll x xss = transpose $ 
       zipWith const
          (transpose [xs ++ repeat x | xs <- xss])         -- pad all, and cut
          (takeWhile id . map or . transpose $             --   to the longest list
             [ (True <$ xs) ++ repeat False | xs <- xss])
    
    > mapM_ print $ padAll '-' ["ommmmmmm", "ommmmmm", "ommmmm", "ommmm", "ommm",
       "omm", "om", "o"]
    "ommmmmmm"
    "ommmmmm-"
    "ommmmm--"
    "ommmm---"
    "ommm----"
    "omm-----"
    "om------"
    "o-------"
    

提交回复
热议问题