我知道在Haskell中构建Map
的几种不同方法:
fromList
从列表中构建fromAscList
从列表中构建列表Map
是Monoid
(或Semigroup
)并合并singletons
的事实。我知道#1的摊销复杂度为O(n * log(n)),其中#2为O(n)。 我猜想#3应该大致相当于#1,并且可能会融合。
摊销很重要,因为默认情况下Haskell是惰性的,即使从Map中查找为O(log(n)),实际上也可以与Map的构造交错本身为O(n * log(n)),实际上可以使查找为O(n * log(n))(尤其是如果您每次需要时都在构建地图时)。如果您使用硬编码的地图,也可能会附加
例如,我是否认为lookup 'b' (fromList [('a', 1), ('b', 2)])
实际上等效于在列表中查找d而无需使用中间Map?
#1和#3之间有什么区别,或者对列表和调用fromList
进行排序吗?
此外,如果我只需要计算一次映射,是否需要确保GHC不内联,以便在函数之间共享?
我意识到这个问题可能有点模糊,实际上与我最近遇到的不同用例相对应。
第一个对应于“静态连接”。我有一个管理商品的应用,每个商品代码都可以按样式和变化形式进行拆分(例如'T-Shirt-Red'=>('T-Shirt','Red')。拆分基于规则(和regexp),而且速度很慢。为了避免每次都重新计算规则,只需执行一次并存储在db表中。我有一些纯函数需要拆分项目代码,因此我将它们传递给函数{ {1}}。该函数实际上是部分应用于地图的查找。代码与此类似
Text -> (Text, Text)
通过使用getSplitter :: Handler (Text -> (Text, Text))
getSplitter = do
sku'style'vars <- runDB $ rawSQL "SELECT sku, style, var FROM style_cache " [] -- load the split table
let sku'map = fromList [ (sku, (style,var))
| (sku, style, var) <- sku'style'vars
]
return $ flip lookup sku'map
对项目进行排序并使用sku
(实际上比fromDistinctAscList
更快)可以很容易地加快速度。但是我仍然有一些关于如何在不同请求之间缓存它的问题。
第二种情况是在两个表之间进行手动联接,我通常会做一些事情
fromAscList
再次可以在SQL中对sku'infos进行排序,并使用fromDistinctAscList。
第三种情况是在与不同表中的类别项目有关的其他信息的获取中。
例如,我希望能够按类别比较销售(销售表)和购买(购买表)。
在纯SQL中,我会做些事情
do
sku'infos <- selectList [] [] -- load item info
let skuInfo = fromList sku'infos
orderLines <- selectList [] [] -- load orders
-- find infos corresponding to order items
mapM (\o -> (o, lookup (orderSku o) skuInfo) orderLines
但是,这是一个简化的示例,实际上,聚合要复杂得多,必须在Haskell和联接中完成。为此,我要分别加载每个表(对sql中的内容进行分组)并返回SELECT style, sum(sales.amount), sum(purchase.amount)
FROM style_cache
LEFT JOIN sales USING(sku)
LEFT JOIN purchases USING(sku)
GROUP by style
,Map Style SalesInfo
等...并合并它们。该表很大,我意识到我最终将所有内容加载到内存中,而我可能可以通过手动“压缩”文件来提高效率,但是我不确定如何加载。
答案 0 :(得分:2)
我不确定我是否理解这个问题的全部动机,但我会发表一些评论:
Map
是严格限制的-这意味着Map
的树结构和键本身被强制(至少足够远,可以进行所有必要的比较) }操作。因此,我希望Map
进行O(n * log(n))比较(n为Data.Map.lookup k (fromList xs)
的长度),而我期望xs
进行O(n)比较(实际上只是进行相等性检查,但通常它的复杂度与比较差不多。Prelude.lookup k xs
的速度确实比fromAscList . sort
快,则这是fromList
中的性能错误,应只更改库以定义Data.Map
。如果真是这样,我会感到非常惊讶。人们花了很多时间优化fromList = fromAscList . sort
,所以我不希望看到有那么低的成果。