我想知道是否会有一种简洁/单行的方式来执行以下操作:
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]
我对这两个选项中的任何一个都没有太多反对意见,但我想知道:将(,)
与其他函数相结合是否有更简洁的方法?
我曾经假设有这样的方式,但它让我望而却步。所以这只是出于好奇。
谢谢!
答案 0 :(得分:4)
我们可以轻松地将列表拆分为两个列表,其中包含带有此潮汐的交替元素(due to HaskellWiki)
foldr (\a ~(x,y) -> (a:y,x)) ([],[])
剩下的就是将列表与zip
pack :: [a] -> [(a, a)]
pack = uncurry zip . foldr (\a ~(x,y) -> (a:y,x)) ([],[])
答案 1 :(得分:2)
使用LambdaCase
和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 ]
答案 2 :(得分:1)
请注意,对于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)
答案 3 :(得分:0)
我不知道这是否是一行,但是:
snd $ foldr (\ x (z, ps) -> maybe (Just x, ps) (\y -> (Nothing, (x, y) : ps) z) (Nothing, []) $ xs
应与您的功能相同。