Haskell-使用折叠将成对的列表分成两个列表

时间:2019-01-10 12:25:55

标签: list haskell fold

因此,我得到了一个包含元组的列表,我需要将其分解为两个列表,第一个列表包含具有奇数索引的元素,第二个列表包含具有偶数索引的元素,必须使用fold完成是我的尝试:

breakList :: [(Integer, Integer)] -> [[(Integer, Integer)]]
breakList [] = [[], []]
breakList xxs@(x:xs) = foldl (\ acc y -> if length (acc !! 0) < length (acc !! 1) then y : (acc !! 0) else y : (acc !! 1)  )  [[], []] xxs

我得到的错误:

无法匹配类型“((整数,整数)”)  与[[(Integer,Integer)]'       预期的类型:[[((Integer,Integer)]]

悬停在y : (acc !! 1) and y : (acc !! 0)

示例:

输入:

  

ex1 = [(2,2),(1,3),(2,3),(2,4),(3,5),(0,2),(2,1),(1 ,4)   ,(2,0),(1、2),(3,1),(1,0)]

输出

  

breakList ex1   ==([[2,2),(2,3),(3,5),(2,1),(2,0),(3,1)],[(1,3),(2 ,4),(0,2),(1,4),(1,2),(1,0)])

2 个答案:

答案 0 :(得分:2)

请注意,您要将一个列表分成两个成对的列表,因此返回类型应为

([(Integer, Integer)], [(Integer, Integer)])

不是

[[(Integer, Integer)]]

并访问对的元素,可以使用fstsnd而不是通过索引,最后,使用foldl将以相反的顺序返回结果列表,可以固定使用foldr代替。更正如下:

breakList :: [(Integer, Integer)]->([(Integer, Integer)], [(Integer, Integer)])
breakList xxs = foldr (\y acc-> if length (fst acc) < length (snd acc)
                                then (y:(fst acc), snd acc)
                                else (fst acc, y:(snd acc)) ) ([], []) xxs

答案 1 :(得分:2)

威廉姆(Willem)在评论中所暗示的,这里的标准技巧是我几年前在[user:Ed'ka]的一个(F#或Ocaml)回答中关于SO的。

evenodds :: [a] -> ([a], [a])
evenodds xs = foldr g ([],[]) xs
  where
  g x ~(as,bs) = (bs,x:as)

oddevens :: [a] -> ([a], [a])
oddevens xs = foldr g ([],[]) xs
  where
  g x ~(bs,as) = (x:as,bs)

从这里开始,奇数位置是什么,从列表上的第一位开始甚至是偶数位置。

波浪号~引入了一种惰性模式,以便该函数在其操作中正确地处于惰性状态。