[英]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)) ([],[])
使用LambdaCase
和Data.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.