Haskell 如何压缩不同长度的列表?
我怎样才能Haskell 如何压缩不同长度的列表?,haskell,Haskell,我怎样才能zip像这样的两个列表 ["Line1","Line2","Line3"] ["Line4","Line5"] 不丢弃第一个列表中的rest元素 如果可以的话,我想用空列表压缩额外的元素 zipWithPadding :: a -> b -> [a] -> [b] -> [(a,b)] zipWithPadding a b (x:xs) (y:ys) = (x,y) : zipWithPadding a b xs ys zipWithPadding a _ [
zip
像这样的两个列表
["Line1","Line2","Line3"]
["Line4","Line5"]
不丢弃第一个列表中的rest元素
如果可以的话,我想用空列表压缩额外的元素
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)
只要有元素,我们就可以简单地压缩它们。一旦元素用完,我们就用一个无限的padding元素列表来压缩剩余的列表
在您的情况下,您可以将此用作
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
这只是对齐塔人方法的阐述。然后将该函数实现为(使用{-#语言元组{-}):
好吧,如果你不丢弃它们,你还能做什么?把短名单填上?如果是,使用什么值?我编辑我的问题。如果在
zip
之后会出现类似(“string”,[])
zip list的重复元素a$list\u b++repeat”“@Riccardo我不认为这更好,在不一定有Monoid的情况下,公认的答案会起作用,并且可能希望对不同的拉链使用不同的默认值。数据可能对
没有好的意义,但仍然会有一个健全的内存(或多个健全的默认值)。Haskell的最佳实践是使用尽可能少的限制类型,使用Monoid
对该函数的限制超出了必要的范围,因为没有使用
。此外mzip
可以通过将mempty
传递给这两个默认值来定义zipWithPadding
。@Riccardo我个人认为,如果标准库定义了class Default m where mempty::m
和class Default m=>Monoid m where mappend::m->m->m
@Riccardo:mzip=zipWithPadding mempty mempty
。仅仅因为某些东西使用了Monoid
并不能使它更好或更强大;)。我看我的评论肯定太短了,不能不被误解,让我澄清一下:)我同意这样一个事实,zipWithPadding
解决方案更一般,毫无疑问。但是问题是关于字符串列表的,因为OP明确要求使用“
填充。在这方面,涉及幺半群的解决方案不仅对于OP来说足够一般,而且比必须指定两个不会改变的默认参数更简单。这就是我最喜欢mempty
解决方案的原因。看起来有人已经在数据默认值中实现了Default
类。您可以使用签名(默认a,默认b)=>[a]->[b]->[(a,b)]
编写mzip
,并用def
替换mempty
。它已经有许多常见类型的实例,因此如果我已经依赖于该包,那么在这种情况下我将选择它。请注意那些想要查看mempty
或Monoid
的人:zipWithPadding mempty mempty
将为您提供(monoidA,monoidB)=>[a]->[b]->[(a,b)]
。
zipWithPadding a b as bs = zipWithOr (,) (,b) (a,) as bs