我有一个列表,我希望将列表分成两个,一个包含偶数索引中的元素,另一个包含奇数索引中的元素。
breakByIndexes :: [a] -> ([a], [a])
例如:
> breakByIndexes ["A", "B", "C", "D"]
(["A", "C"], ["B", "D"]
> breakByIndexes ["A", "B", "C", "D", "E"]
(["A", "C", "E"], ["B", "D"]
我得到了这样的解决方案
breakByIndexes [] = ([], [])
breakByIndexes [e] = ([e], [])
breakByIndexes (e:o:xs) =
let (es, os) = breakByIndexes xs
in (e : es, o : os)
但我很好奇是否可以在不使用递归的情况下实现?
是否可以通过编写Data.List
?
答案 0 :(得分:6)
是的,你是对的,使用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")
我是怎么发现的?转到Hoogle并填写[a] -> ([a], [a])
。
答案 1 :(得分:6)
我最喜欢的此功能版本使用foldr
pairs = foldr (\x ~(ys,zs) -> (x:zs,ys)) ([],[])
它通过在列表中的每个项目上交换元组来工作。封闭内部:
\x ~(odds,evens) -> (x:evens, odds)
您添加x
,这意味着现在,evens列表中的所有其他元素成为奇数元素。
~
的内容是什么?它使模式匹配 lazy 。没有它,你就会强制元组。所以,例如,如果我写道:
(head . fst . pairs) [1..]
如果没有~
,它就无法运作。你可以通过写:
pairs = foldr (\x yszs -> (x:snd yszs,fst yszs)) ([],[])
或者:
pairs = foldr (\x -> uncurry (\ys zs -> (x:zs,ys))) ([],[])
答案 2 :(得分:5)
这是另一种方式。与发布时的其他答案不同,它自然地推广到2以外的其他模数。
Data.List Data.List.Split> transpose . chunksOf 2 $ "ABCDE"
["ACE","BD"]
答案 3 :(得分:0)
编辑:由于@DanielWagner打开了大门,如果可以返回列表而不是元组,那么显而易见的解决方案是:
[[x | (x,i)<-zip xs [0..], i `mod` 2 == j] | j<-[0..1]]
可以概括为:
[[x | (x,i)<-zip xs [0..], i `mod` k == j] | j<-[0..k-1]]
对于k个元素列表[[e_0,e_k,e_2k,...],[e_1,e_k + 1,e_2k + 1,...],...,[e_k-1,e_2k-1, e_3k-1,...]]。
对于元组,我留下以前的代码记录,虽然它明显比其他答案更差。
使用列表理解很容易选择偶数元素:
Prelude> evens xs = [x | (x,i) <- zip xs [0..], even i]
Prelude> evens ["A", "B", "C", "D", "E"]
["A","C","E"]
您可以对奇数元素执行相同操作。但是你也可以定义一个带过滤器(even
或odd
)并返回一个选择元素的函数的函数:
Prelude> toFilter xs = \f -> [x | (x,i) <- zip xs [0..], f i]
Prelude> :t toFilter ["A", "B", "C", "D", "E"]
toFilter ["A", "B", "C", "D", "E"]
:: (Num t, Enum t) => (t -> Bool) -> [[Char]]
toFilter xs
采用过滤器并返回一个列表:
Prelude> l = toFilter ["A", "B", "C", "D", "E"]
Prelude> l even
["A","C","E"]
Prelude> l odd
["B","D"]
也可以两个定义一个函数,它接受toFilter
((t -> Bool) -> [[Char]]
)之类的函数,并为even
和odd
过滤器创建一个元组:< / p>
Prelude> :t \tf -> (tf even, tf odd)
\tf -> (tf even, tf odd) :: Integral a => ((a -> Bool) -> t) -> (t, t)
现在,把事情放在一起很容易:
Prelude> breakByIndexes xs = (\tf -> (tf even, tf odd)) (\f -> [x | (x,i)<-zip xs [0..], f i])
Prelude> breakByIndexes ["A", "B", "C", "D"]
(["A","C"],["B","D"])
Prelude> breakByIndexes ["A", "B", "C", "D", "E"]
(["A","C","E"],["B","D"])
不如@ elemx80s优雅,但做得好......
答案 4 :(得分:0)
请记住,ASCII字符的内置索引偏移量为65。
导入Data.Char(ord)
ord 'A' - 65
= 0`
没有偏移量,数值无论如何都是偶数和奇数。 'A'是65,奇数。
p l = [ [x|x<-l,odd (ord(head x))], [x|x<-l,even (ord(head x))] ]
我爱对。一旦数据集成对,就可以更容易地使用。我遇到了一个为这个集合创建完美对的函数,它在末尾但在列表中留下了不成对的元素。它不会创建元组,但列表对也可以。该函数是chunksOf。
这里用作
i3 = chunksOf 2 $ words "A B C D E F G H I"
生成我们想要的对。 [["A","B"],["C","D"],["E","F"],["G","H"],["I"]]
对是偶数对。最后一个奇怪的人真的缺少一个奇怪的成员。列表中的所有奇数元素都缺少奇数成员。奇数成员提取器必须补偿少于两个成员的对的过滤器。
[ map (head) l3, map (last) (filter ((>1).length) l3) ]
制作[["A","C","E","G","I"],["B","D","F","H"]]
对携带信息,例如偶数或奇数。
令我震惊和敬畏的@DanielWagner指出transpose
使用配对列表产生了预期的结果。他的transpose i3
是一个非常简洁的解决方案。哇!
编辑4/15/2018
我希望这是最终的或接近最终的。
let ls = words "A B C D E F G"
[[a|(a,b)<-zip ls [0..],bl b]|bl<-[even,odd]]
[[ “A”, “C”, “E”, “G”],[ “B”, “d”, “F”]]