我目前有一份表格清单:
[(foo, bar), (foo, baz), (qux, quux)]
我想将其转换为表单列表:
[(foo, [bar, baz]), (qux, [quxx])]
在我的实际用例中,该列表包含大约100万个这些元组。
目前,我正在通过以下方式解决这个问题,虽然它完全是纯粹的,没有副作用,但也是(据我所知)O(n^2)
:
import qualified Data.HashMap.Strict as M
foo xs = M.fromListWith (++) $ xs
有更好的方法吗?
答案 0 :(得分:2)
fromListWith
算法has an O(n*log n)
time complexity。没有其他限制,这是你能得到的最好的。这个想法是你需要遍历列表(O(n)
)和foreach元素插入(并检查重复)哈希中的键(O(log(n))
)。
通过其他约束和更大的空间复杂性,您可能能够实现线性复杂性。例如,如果键的范围是“紧凑”而键是整数,那么您可以使用矢量/数组,并且可能在空间方面支付更多,但获得O(1)
查找和插入。
答案 1 :(得分:1)
不,你没事,除了你的实施中的一个小错误[1]。正如杰弗里指出的那样,fromListWith
具有 O(n log n)的复杂性,这非常好。
您可能遇到的潜在问题是附加,如果所有键都相同并且您附加到每个列表的末尾,则可能是 O(n ^ 2)。然而,一个小实验显示
data Tree a = Branch (Tree a) (Tree a) | Leaf a
deriving (Show)
ghci> M.fromListWith Branch [(1, Leaf 1), (1, Leaf 2), (1, Leaf 3)]
fromList [(1,Branch (Leaf 3) (Branch (Leaf 2) (Leaf 1)))]
fromListWith
将新元素作为组合函数的第一个参数,因此您将前置( O(1))而不是追加(这是 O(n)),所以你可以在那里。
[1]:在传递给M.fromListWith
之前,您忘记从值中制作单例列表。