首页 文章

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

提问于
浏览
9

我怎么能 zip 两个列表像

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

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

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

5 回答

  • 8

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

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

    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
    
  • 0

    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
    

相关问题