说我有一个矢量:
(def data ["Hello" "World" "Test" "This"])
我想在一个有api的地方填充一张桌子:
(defn setCell
[row col value]
(some code here))
那么让以下调用发生的最佳方法是什么:
(setCell 0 0 "Hello")
(setCell 0 1 "World")
(setCell 0 2 "Test")
(setCell 0 3 "This")
我发现以下内容可行:
(let [idv (map vector (iterate inc 0) data)]
(doseq [[index value] idv] (setCell 0 index value)))
但有没有更快的方法不需要新的临时数据结构idv?
答案 0 :(得分:27)
只需将索引与数据一起映射,就可以以非常方式的方式获得相同的效果。
(map #(setCell 0 %1 %2) (iterate inc 0) data)
您可能希望将其包含在(doall
或(doseq
中,以便现在进行调用。将无限seq与有限seq一起映射就好了,因为当最短的seq用完时,map将停止。
答案 1 :(得分:27)
游戏有点晚,但访问此页面的人:现在(自clojure 1.2以来)clojure.core中有map-indexed
函数。
一个问题(除非我弄错了):没有“pmap”等价,这意味着地图索引计算不能轻易并行化。在这种情况下,我会参考上面提供的解决方案。
答案 2 :(得分:10)
你这样做的方式是惯用的(事实上与clojure.contrib.seq-utils/indexed
相同)。如果您真的想避免额外的数据结构,可以这样做:
(loop [data data, index 0]
(when (seq data)
(setCell 0 index (first data))
(recur (rest data) (inc index))))
我会使用你的版本,除非有充分的理由不这样做。
答案 3 :(得分:8)
最好的方法是使用clojure.contrib.seq-utils/indexed
,它看起来像这样(使用解构):
(doseq [[idx val] (indexed ["Hello" "World" "Test" "This"])]
(setCell 0 idx val))
答案 4 :(得分:1)
我做了一个简短的比较选项的性能:
; just some function that sums stuff
(defn testThis
[i value]
(def total (+ total i value)))
; our test dataset. Make it non-lazy with doall
(def testD (doall (range 100000)))
; time using Arthur's suggestion
(def total 0.0)
(time (doall (map #(testThis %1 %2) (iterate inc 0) testD)))
(println "Total: " total)
; time using Brian's recursive version
(def total 0.0)
(time (loop [d testD i 0]
(when (seq d)
(testThis i (first d))
(recur (rest d) (inc i)))))
(println "Total: " total)
; with the idiomatic indexed version
(def total 0.0)
(time (let [idv (map vector (iterate inc 0) testD)]
(doseq [[i value] idv] (testThis i value))))
(println "Total: " total)
我的1核笔记本电脑的结果:
"Elapsed time: 598.224635 msecs"
Total: 9.9999E9
"Elapsed time: 241.573161 msecs"
Total: 9.9999E9
"Elapsed time: 959.050662 msecs"
Total: 9.9999E9
初步结论:
使用循环/重复解决方案。