大型浮动列表的查找功能 - 记忆计算?

时间:2013-10-10 12:00:47

标签: c# f#

我需要为大型列表编写查找函数(float * float)。如果未找到密钥,则此函数应添加新条目;如果找到密钥,则应添加总和值。我已经阅读了关于memoized计算的内容,实际上并不是很难做到的。这就是我所拥有的:

let memoLookUp basearr lookarr =
    let t = new System.Collections.Generic.Dictionary<float,float>()
    for (a,b) in basearr do
        t.Add(a,b)
    for (a, b) in lookarr do
        if t.ContainsKey(a) then t.[a] <- t.[a] + b
        else t.Add(a,b)
    t

示例数据:

let basearr = [(41554., 10.0) ; (41555., 11.0) ; (41556., 12.0) ; (41557., 10.0) ; (41558., 13.0) ]

let lookarr = [(41555., 14.0) ; (41556., 15.0) ; (41559., 16.0)]

按预期返回。

我的问题是:

  • 如果列表很长(比如大约30000个),那么从性能的角度来看这样做是否明智?
  • 或者按日期排序(在每个数据列表的第一列中)然后使用更强制性的方法会更好吗?
  • 或者甚至是在f#或c#中构建?

2 个答案:

答案 0 :(得分:4)

您现有的代码可能会合并两个数组,以实现更统一的行为。除非另有要求,(例如, 想要 如果basearr包含重复,程序会崩溃)制服更好

let incrementalAdderImperative aseq = 
  let d= System.Collections.Generic.Dictionary<_,_>()
  Seq.iter(fun (k,v) ->  if d.ContainsKey(k) 
                         then d.[k] <- d.[k] + v
                         else d.Add(k,v)) aseq

回答你的问题:

  •   

    如果列表很长(比如大约30000个),那么这样做是明智的   从性能的角度来看这是这样的吗?

您正在使用基于哈希的字典,依赖于Dictionary类。所以它根本不应该降级。请注意,这是字典的实现的属性,而不是IDictionary中描述的字典功能。还有其他实现(例如Map)

如果您担心性能问题,则应该使用(快速)估计将会发生多少密钥来初始化字典,以避免内部调整大小。并了解所使用的具体类型(如基于哈希的字典等)。

  •   

    最好按日期排序(在每个数据的第一列中)   列表),然后使用更迫切的方法?

如果按日期排序,则可以进行折叠。我认为这会更快,但你提到的数字并不是那么大。

let oneshotAdder reducer kvArr =
    kvArr |> Array.sortInPlaceBy fst
    let a = kvArr 
            |> Array.fold(fun (res) (k,v) ->  
                            match res with
                            | []                             -> (k,v)::res
                            | ((prevk,_)::xs) when k = prevk -> (k,reducer v (List.head res |> snd))::(List.tail res)
                            | _                              -> (k,v)::res)
                          List.empty
    dict a
let data = Array.concat ([basearr; lookarr] |> List.map List.toArray)
let dict2 = oneshotAdder (+) data

ps:在你给出的例子中,basearr和lookarr是列表,而不是数组,因此假设你确实想要对数组进行操作,这是无关的操作。

  •   

    甚至在f#或c#中都有内置?

在F#中,你可以原生地创建一个groupby,然后对它们求和。集合变换的本质是传递函数,因此本质上不需要它。 在C#中,你可以使用Linq来获得这样的枚举变换,这些变换在引擎盖下映射到fsharp中的一些函数。

let groupByAdder reducer (kvArr:('k*'v) array)  =
    kvArr |> Seq.groupBy fst 
          |> Seq.map (fun (k,vs) -> k , vs |> Seq.map snd |> (Seq.reduce reducer)) 
          |> dict
let dict3 = groupByAdder (+) data 

答案 1 :(得分:1)

我愿意:

Seq.groupBy fst kvs
|> Seq.map (fun (k, vs) -> k, Seq.map snd vs |> Seq.reduce (+))
|> dict