我认为我需要像折叠或者折叠的东西,但我见过的例子似乎只是将列表压缩成一个简单的标量值。
我需要记住并重新使用列表中前一行的值(基本上是“分组依据”操作)
如果我的输入数据如下:
[["order1", "item1"],["", "item2"],["","item3"],["order2","item4"]]
最终采用以下方法的正确方法是什么:
[["order1",["item1","item2","item3"]],["order2",["item4"]]
即data Order = Order { id :: Text, items :: [OrderItem]}
如果我想要一个稍微不同的结构怎么办?
[("order1",["item1","item2","item3"]),("order",["item4"])]
即data OrderTuple = OrderTuple { order :: Order, items :: [OrderItem]}
如果我还想从OrderItem保持一些数值的运行总结怎么办?
编辑:这是我试图根据Frerich的答案开始工作的代码
--testGroupBy :: [[String]] -> [[String]]
testGroupBy :: [[String]] -> [(String, [String])]
testGroupBy z =
--groupBy (\(x:xs) (y:ys) -> x == y || null y) z
groupBy testFunc z
testFunc :: [String] -> [String] -> Bool
testFunc (x:xs) (y:ys) = x == y || null y
答案 0 :(得分:2)
模式匹配在这里很有用
groupData = foldl acc []
where acc ((r, rs):rss) ("":xs) = (r, rs ++ xs): rss
acc rss (x:xs) = (x, xs): rss
acc _ _ = error "Bad input data"
结果组的顺序相反,如果需要,请使用reverse
。
如果我想要一个稍微不同的结构怎么办?
只需将一个变换为另一个,您可以在groupData
内部或作为单独的函数进行。
如果您接受没有fst
元素的初始群组
groupData = foldr acc []
where acc (x:xs) [] = [(x, xs)]
acc ("":xs) (("", rs):rss) = ("", rs ++ xs): rss
acc (x:xs) (("", rs):rss) = (x, rs ++ xs): rss
acc (x:xs) rss = (x, xs): rss
然后
let xs = [["", "item8"],["", "item9"],["order1", "item1"],["", "item2"],["","item3"],["order2","item4"]]
print $ groupData xs
是
[("",["item9","item8"])
,("order1",["item3","item2","item1"])
,("order2",["item4"])]
答案 1 :(得分:1)
我首先尝试查看是否可以将函数定义为更高级函数的组合(例如fold
),而不是寻找基于map
的解决方案。让我开火ghci
会话并玩abit:
λ: let x = [["order1", "item1"],["", "item2"],["","item3"],["order2","item4"]]
您的“分组依据”操作实际上有一个现有名称:Data.List.groupBy
- 这几乎可以满足我们的需求:
λ: import Data.List
λ: let x' = groupBy (\(x:xs) (y:ys) -> x == y || null y) x
λ: x'
[[["order1","item1"],["","item2"],["","item3"]],[["order2","item4"]]]
此groupBy
应用程序将x
中的所有元素放入第一个元素相等的一个组(即列表)中,或者第二个元素为空。然后可以按照您想要的格式进行按摩(在这种情况下,您使用map
建议的第二个):
λ: let x'' = map (\x -> (head (head x), map (!! 1) x)) x'
λ: x''
[("order1",["item1","item2","item3"]),("order2",["item4"])]
全部放在一起:
groupData :: [[String]] -> [(String, [String])]
groupData = map (\x -> (head (head x), map (!! 1) x))
. groupBy (\(x:xs) (y:ys) -> x == y || y == "")
我认为通过这种方式,构建一个合适的数据结构(即比嵌套列表更安全的类型)应该是直截了当的。