我怎样才能
zip
两个类似的列表
["Line1","Line2","Line3"]
["Line4","Line5"]
不丢弃第一个列表中的其余元素?
如果可以的话,我想用空列表压缩额外的元素。
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","")]
另一个解决方案是创建一个适用于幺半群的 zip 函数,并用 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","")]
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
我认为如果你是 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)
有时我不想填满我的清单。例如,当我只想压缩等长列表时。这是一种通用解决方案,如果一个列表较长,它可能会返回任何额外的值。
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 bs
,svs
可以是以下三种情况之一: Just (Left x)
,其中 as
的剩余物返回为 x
, Just (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
我知道这是一个老问题,但为了文档的缘故,一个更简单的解决方案是:
{- | Zip two lists together, padding the shorter list with `Nothing` values so all values
in either list are conserved.
-}
zipPadded :: forall a b. [a] -> [b] -> [(Maybe a, Maybe b)]
zipPadded as bs =
zip ((Just <$> as) <> repeat Nothing) ((Just <$> bs) <> repeat Nothing)
& takeWhile (not . bothNothing)
where
bothNothing (Nothing, Nothing) = True
bothNothing _ = False
这可以由填充默认值等的函数组成