繁体   English   中英

将列表中的(相邻)元素打包为2元组的方法

[英]Ways to pack (adjacent) elements of a list into 2-tuples

我想知道是否会有一个简洁/单行的方式来执行以下操作:

pack :: [a] -> [(a, a)]
pack []       = []
pack [_]      = []
pack (x:y:xs) = (x, y) : pack xs

这与以下相同:

pack' xs = [(x, y) | (x, y, i) <- zip3 xs (tail xs) [0..], even i]

我对这两个选项中的任何一个都没有太多反对,但我想知道:通过将(,)与其他函数组合起来是否有更简洁的方法?

我以为会有这样的方法,但这使我难以理解。 因此,这只是出于好奇。

谢谢!

我们可以轻松地将列表拆分为两个列表,其中包含交替元素与此花絮由于HaskellWiki

 foldr (\a ~(x,y) -> (a:y,x)) ([],[])

剩下的就是将列表与zip合并

pack :: [a] -> [(a, a)]
pack = uncurry zip . foldr (\a ~(x,y) -> (a:y,x)) ([],[])

使用LambdaCaseData.List.unfoldr另一个Data.List.unfoldr

pack = unfoldr $ \case (x:y:zs) -> Just ((x,y),zs); _ -> Nothing

我偶尔想要的东西是splits -

splits :: Int -> [a] -> [[a]]
splits n = unfoldr $ \case [] -> Nothing ; xs -> Just $ splitAt n xs

鉴于此, pack变成:

pack xs = [ (a,b) | [a,b] <- splits 2 xs ]

请注意,对于xs = [x1, x2, ..., xn-1, xn] ,我们有

init xs = [x1, x2, ... , xn-1]
tail xs = [x2, x3, ... , xn  ]

导致

zip (init xs) (tail xs) = [(x1, x2), (x2, x3), (x3, x4), ...]

我们想要的是什么

pack xs                 = [(x1, x2),           (x3, x4), ...]

一旦我们有一个面具列表,这很容易获得

cycle [True, False]     = [ True,    False,    True, ...    ]

导致单线

pack :: [a] -> [(a, a)]
pack xs = map snd . filter fst . zip (cycle [True, False]) $ zip (init xs) (tail xs)

我不知道这是否是一行,但是:

snd $ foldr (\ x (z, ps) -> maybe (Just x, ps) (\y -> (Nothing, (x, y) : ps) z) (Nothing, []) $ xs

应该与你的功能相同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM