我有一个列表,我想将列表分成两个,一个是偶数索引中的元素,另一个是奇数索引.
breakByIndexes :: [a] -> ([a], [a])
例如:
> breakByIndexes ["A", "B", "C", "D"]
(["A", "C"], ["B", "D"]
> breakByIndexes ["A", "B", "C", "D", "E"]
(["A", "C", "E"], ["B", "D"]
Run Code Online (Sandbox Code Playgroud)
我得到了这样的解决方案
breakByIndexes [] = ([], [])
breakByIndexes [e] = ([e], [])
breakByIndexes (e:o:xs) =
let (es, os) = breakByIndexes xs
in (e : es, o : os)
Run Code Online (Sandbox Code Playgroud)
但我很好奇是否可以在不使用递归的情况下实现?是否可以通过编写现有函数来实现Data.List?
是的,你是对的,使用的partition功能Data.List.
Prelude Data.List> (s, u) = partition (even . fst) (zip [0 .. ] "ABCD")
Prelude Data.List> (_, s2) = unzip s
Prelude Data.List> (_, u2) = unzip u
Prelude Data.List> (s2, u2)
("AC","BD")
Run Code Online (Sandbox Code Playgroud)
我是怎么发现的?去Hoogle并填写[a] -> ([a], [a]).
我最喜欢的这个功能版本使用 foldr
pairs = foldr (\x ~(ys,zs) -> (x:zs,ys)) ([],[])
Run Code Online (Sandbox Code Playgroud)
它的工作原理是在列表中的每个项目上交换元组.封闭内部:
\x ~(odds,evens) -> (x:evens, odds)
Run Code Online (Sandbox Code Playgroud)
你添加了x,这意味着均衡列表中的所有其余元素现在变成奇数元素.
有什么~用?它使模式匹配变得懒惰.没有它,你将强制元组.所以,例如,如果我写道:
(head . fst . pairs) [1..]
Run Code Online (Sandbox Code Playgroud)
没有这个就行不通~.您可以通过编写来实现相同的效果:
pairs = foldr (\x yszs -> (x:snd yszs,fst yszs)) ([],[])
Run Code Online (Sandbox Code Playgroud)
要么:
pairs = foldr (\x -> uncurry (\ys zs -> (x:zs,ys))) ([],[])
Run Code Online (Sandbox Code Playgroud)
这是另一种方式.与发布时的其他答案不同,它自然地推广到2以外的其他模数.
Data.List Data.List.Split> transpose . chunksOf 2 $ "ABCDE"
["ACE","BD"]
Run Code Online (Sandbox Code Playgroud)