我写了以下两个函数。
pair :: [a] -> [(a, a)]
pair [] = []
pair [x] = []
pair (x1:x2:xs) = (x1, x2) : pair xs
unpair :: [(a, a)] -> [a]
unpair [] = []
unpair ((x1, x2):xs) = x1 : x2 : unpair xs
Pair将采用成对的元素并制作它们的2元组。如果列表具有奇数个元素,则丢弃最后一个元素。 Unpair是对的反面。
这些工作,但想知道是否有更简洁的方法来编写这些。
答案 0 :(得分:5)
一行程序:
pair xs = map snd . filter fst . zip (iterate not True) $ zip xs (drop 1 xs)
unpair = concatMap (\(x,y) -> [x,y])
您也可以将pair
的定义略微缩写为:
pair (x1:x2:xs) = (x1, x2) : pair xs
pair _ = []
答案 1 :(得分:4)
它不再简洁,但为了清楚起见,我会使用splitEvery
pair
pair = map tuplify . filter ((>1) . length) . splitEvery 2
where
tuplify [x, y] = (x, y)
:
unpair
这是我的头脑 - 只检查最后一个列表的长度会更好。
对于foldr
,我使用unpair = foldr (\(x, y) -> (x:) . (y:)) []
来避免显式递归:
{{1}}
这只是一个品味问题。
答案 2 :(得分:2)
有这么多可能性。这些怎么样?
unpair' = concatMap (\(x,y) -> [x,y])
pair' xs = map snd . filter fst . zip (cycle [True, False]) $ zip xs (tail xs)
pair'' xs = [(x,y) | (True,x,y) <- zip3 (cycle [True,False]) xs (tail xs)]
对的两个版本应该是相同的。
编辑:关于我上面的评论,可以使用Hackage中的拆分包来编写:
pair xs = map head . splitEvery 2 $ zip xs (tail xs)
更接近所需的
pair xs = everyOther $ zip xs (tail xs)
但是,本着毫无意义的精神,我认为我们应该大家都同意写它,
pair = map head . splitEvery 2 . (zip <$> id <*> tail)
以确保混淆。
答案 3 :(得分:1)
pair s = dropEven $ zip s (tail s)
where dropEven s = map fst $ filter snd $ zip s (cycle [True, False])
unpair = concatMap (\(a, b) -> [a, b])
虽然我绝对更喜欢你对pair
的定义。
答案 4 :(得分:1)
这对view patterns非常有用:
{-# LANGUAGE ViewPatterns #-}
pair :: [a] -> [(a,a)]
pair (splitAt 2 -> ([x,y],ys)) = (x,y) : pair ys
pair _ = []
unpair :: [(a,a)] -> [a]
unpair = (>>= \(x,y) -> [x,y])