Map 从clojure映射向量求和字符串值

Map 从clojure映射向量求和字符串值,map,clojure,Map,Clojure,我有一个地图向量,如下所示,尽管每个数据集中可能有100个地图: data({ a:a b:"2" c:t}{ a:b b:"0" c:t}{ a:c b:"-4" c:t}{ a:d b:"100" c:t}{ a:e b:"50" c:t}) 我需要得出:b的和 values(map :b data) sum(reduce + (map read-string values) 这给出了期望的结果,但计算时间很长,约为每秒1/10。我这样做是为了几十万个数据集,所以这样做会占用大量的处理时

我有一个地图向量,如下所示,尽管每个数据集中可能有100个地图:

data({ a:a b:"2" c:t}{ a:b b:"0" c:t}{ a:c b:"-4" c:t}{ a:d b:"100" c:t}{ a:e b:"50" c:t})
我需要得出:b的和

values(map :b data)
sum(reduce + (map read-string values)
这给出了期望的结果,但计算时间很长,约为每秒1/10。我这样做是为了几十万个数据集,所以这样做会占用大量的处理时间

有人能提出一种更有效/更快的方法吗


谢谢

您可以尝试使用
Integer/parseInt
Long/parseLong
而不是更通用的
读取字符串

[编辑]

Clojure 1.5.1的一个简单测试表明,parseInt的速度大约快10倍:

user=> (time (dotimes [n 100000] (read-string "10")))
"Elapsed time: 142.516849 msecs"
nil

user=> (time (dotimes [n 100000] (Integer/parseInt "10")))
"Elapsed time: 12.754187 msecs"
nil
一种可能性是使用并行运行的:

(require '[clojure.core.reducers :as r])
(r/reduce + (r/map read-string values)) 

对于小型测试用例,这不会提高运行时间,但对于大型数据集,它应该会提高运行时间。

这是在Clojure 1.2.1上,在10万个数据集场景中,在1/10秒多一点的时间内完成的十分之一。它基本上是您的代码(这不是真正有效的clojure语法,但我们得到了要点),但不知何故运行速度是10.000x

;generate 10.000 datasets of 100 maps having 10 fields each

(def scenario-data
    (vec (repeatedly 10000
                     (fn [] (vec (repeatedly 100 (fn [] (zipmap
                                                            [:a :b :c :d :e :f :g :h :i :j]
                                                            (repeatedly (fn [] (str (- (rand-int 2000) 1000))))))))))))


;now map the datasets into the reduced sums of the parsed :b fields of each dataset

(time (doall (map (fn [dataset] (reduce (fn [acc mp] (+ acc (Integer/parseInt (:b mp)))) 0 dataset))
                  scenario-data)))
"Elapsed time: 120.43267 msecs"
=> (2248 -6383 7890 ...)
由于此场景占用大量内存(10000个数据集~=600MB,总计算量使用~4GB),因此我无法在家用计算机上运行100000个数据集场景。但是,如果我不将数据集保存在内存中,而是映射一个惰性序列而不保留其头部,则可以运行它

(time (doall (map (fn [dataset] (reduce (fn [acc mp] (+ acc (Integer/parseInt (:b mp)))) 0 dataset))
                  (repeatedly 100000
                              (fn [] (repeatedly 100 (fn [] (zipmap
                                                              [:a :b :c :d :e :f :g :h :i :j]
                                                              (repeatedly (fn [] (str (- (rand-int 2000) 1000))))))))))))
"Elapsed time: 30242.371308 msecs"
=> (-4975 -843 1560 ...)
计算100.000数据集版本需要30秒,包括生成数据所需的所有时间。使用
pmap
可将该时间大致缩短一半(4芯)

编辑:在具有足够内存的机器上创建完全实现的100.000个数据集需要135秒。在其上运行求和代码需要约1500毫秒。使用
pmap
可将该值降低至约750毫秒。
读取字符串
版本的速度大约慢3.5倍

TL/DR:如果有足够的内存,您发布的算法可以在1秒内在100.000个数据集场景上运行。


请发布完整的代码,包括如何读取数据集并将其保存在内存中,并确保这次的语法和观察结果都是准确的。由于没有从源代码中懒洋洋地读取数据集,这可能更像是内存问题。

请给出真正的clojure代码,而不是此伪代码。我们可以接受它。这是真正的clojure代码…为什么不将int存储为int而不是string?性能不仅仅来自算法,它是结构+的组合algorithm@redhands不,不是!我试过了,但是我犯了很多错误。不过,说真的,你最好在问题中提供重要信息。就像您使用的是clojure的旧版本一样(哪一个?)@Ankur,谢谢,我尝试过解析源数据,然后运行计算,但性能仍然没有真正的改进我尝试过(reduce+(map#(Integer/parseint%1)值))但这没有什么区别。我喜欢使用减缩器,但不幸的是,我使用的是较旧版本的clojure,如果您可以使用
pmap
获得一些并行性,我将无法随时升级。它可从clojure 1.0获得,因此您应该能够使用它。