Haskell - 使用折叠将两个列表中的对列表分开
Haskell - separate a list of pairs in two lists using 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)]]
悬停在 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)])
请注意,您要将一个列表拆分为一对列表的两个列表,因此 return 类型应为
([(Integer, Integer)], [(Integer, Integer)])
没有
[[(Integer, Integer)]]
并访问pair的元素,可以使用fst
和snd
代替索引,最后,使用foldl
将return中的结果列表相反的顺序,它可以固定使用 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
这里的标准技巧,正如 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)
从这里开始的奇数位置是从列表中更远的位置开始的偶数位置。
波浪号 ~
引入了惰性模式,以便函数在其操作中适当地惰性。
所以,我得到了一个包含元组的列表,我需要将它分成两个列表,第一个列表包含索引为奇数的元素,第二个列表包含索引为偶数的元素,必须使用 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)]]
悬停在 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)])
请注意,您要将一个列表拆分为一对列表的两个列表,因此 return 类型应为
([(Integer, Integer)], [(Integer, Integer)])
没有
[[(Integer, Integer)]]
并访问pair的元素,可以使用fst
和snd
代替索引,最后,使用foldl
将return中的结果列表相反的顺序,它可以固定使用 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
这里的标准技巧,正如 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)
从这里开始的奇数位置是从列表中更远的位置开始的偶数位置。
波浪号 ~
引入了惰性模式,以便函数在其操作中适当地惰性。