【问题标题】:Is it bad to use toList?使用 toList 不好吗?
【发布时间】:2010-10-05 00:36:08
【问题描述】:

假设有 2 个地图

import qualified Data.Map as M
sparse1, sparse2 :: M.Map Int Float
sparse1 = M.fromList [(1,2.0),(10,3),(12,5),(100,7),(102,11)]
sparse2 = M.fromList [(2,13.0),(11,17),(12,19),(101,23),(102,29)]

如何定义优雅的函数

combi :: M.Map Int Float -> M.Map Int Float -> Float

combi sparse1 sparse2 返回 414.0 (= 5 * 19 + 11 * 29) 因为 12 和 102 是两个映射的唯一公共键?列表有一个优雅(简单而高效)的功能,因为它们将被严格排序:

combiList xs ys = cL xs ys 0
cL [] _ acc = acc
cL _ [] acc = acc
cL (x@(k,r):xs) (y@(k',r'):ys) acc 
    | k < k'  = cL xs     (y:ys) acc
    | k == k' = cL xs     ys     (acc+r*r')
    | k > k'  = cL (x:xs) ys     acc

但是

combi m1 m2 = combiList (M.toList m1) (M.toList m2)

知道在其余代码中不再使用列表是个好主意吗?如果没有,你将如何在没有 toList 的情况下有效地编写组合?

【问题讨论】:

    标签: performance list haskell containers


    【解决方案1】:

    在地图上使用foldintersectWith 会更优雅(而且可能更快):

    combi :: M.Map Int Float -> M.Map Int Float -> Float
    combi x y = M.fold (+) 0 $ M.intersectionWith (*) x y
    

    combi sparse1 sparse2 根据需要返回 414.0

    如果您关心性能,请尝试使用Data.IntMap:它应该比这里的Data.Map 快几倍。

    【讨论】:

    • 我同意它更优雅,但它更快吗?我不认为在 GHC 中,Map.intersectionWith 生成地图和 Map.fold 消费地图是融合的,因此如果有很多公共键,这段代码可能会更慢。
    • 在这种情况下,我们无法从 Data.Map 获得真正好的性能。 foldintersectionWith 都是惰性的,会导致创建额外的 thunk。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-13
    • 1970-01-01
    • 2011-12-20
    • 2014-05-08
    • 2012-08-08
    • 1970-01-01
    相关资源
    最近更新 更多