如何压缩不同长度的列表?

时间:2014-03-14 10:54:20

标签: haskell

我如何zip两个列表如

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

不丢弃第一个列表中的休息元素?

我想用空列表压缩额外的元素,如果可以的话。

5 个答案:

答案 0 :(得分:10)

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)

只要有元素,我们就可以简单地压缩它们。一旦我们用完了元素,我们只需用剩余的填充元素列表压缩剩余的列表。

在您的情况下,您可以将其用作

zipWithPadding "" "" ["Line1","Line2","Line3"] ["Line4","Line5"]
-- result: [("Line1","Line4"),("Line2","Line5"),("Line3","")]

答案 1 :(得分:8)

另一种解决方案是制作一个拉链函数,该函数适用于monoid并使用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","")]

答案 2 :(得分:1)

Reite解决方案的另一种实现方式,使用更高阶的功能,只是为了好玩。 :)虽然可能比较慢,因为我猜长度函数需要额外遍历列表。

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

答案 3 :(得分:1)

我认为如果你是Haskell编程的新手

,对你来说会很简单
         zip' :: [String] -> [String] ->[(String,String)]
         zip' [][] = []
         zip' (x:xs)[] = bmi x : zip' xs []
                   where bmi x = (x,"")
         zip' [](x:xs) = bmi x : zip' [] xs
                   where bmi x = ("",x)
         zip' (x:xs) (y:ys) = bmi x y : zip' xs ys
                   where bmi x y = (x,y)    

答案 4 :(得分:1)

有时候我不想填写我的清单。例如,当我想仅压缩相等长度的列表时。这是一个通用的解决方案,如果一个列表更长,它可能会返回任何额外的值。

zipWithSave :: (a -> b -> c) -> [a] -> [b] -> ([c],Maybe (Either [a] [b]))
zipWithSave f    []     []  = ([],Nothing)
zipWithSave f    []     bs  = ([],Just (Right bs))
zipWithSave f    as     []  = ([],Just (Left as))
zipWithSave f (a:as) (b:bs) = (f a b : cs , sv)
  where (cs, sv) = zipWithSave f as bs

使用(zps,svs) = zipWithSave f as bssvs可以是以下三种情况之一:Just (Left x)其中来自as的剩余内容将返回为xJust (Right x)其中返回bs的遗留物,或等长列表中的Nothing

另一个通用目的是为每种情况提供额外的功能。

zipWithOr :: (a -> b -> c) -> (a -> c) -> (b -> c) -> [a] -> [b] -> [c]
zipWithOr _ _  _     []    []   = []
zipWithOr _ _  fb    []     bs  = map fb bs
zipWithOr _ fa _     as     []  = map fa as
zipWithOr f fa fb (a:as) (b:bs) = (f a b) : zipWithOr f fa fb as bs

这只是Zeta方法的详细阐述。然后将该函数实现为(使用{ - #LANGUAGE TupleSections# - }):

zipWithPadding a b as bs = zipWithOr (,) (,b) (a,) as bs