我想使用瞬态来创建大型数据结构。这是没有瞬变的代码:
(into [] (repeat 10 :a))
;; => [:a :a :a :a :a :a :a :a :a :a]
我天真的尝试就是这样:
(persistent! (into (transient []) (repeat 10 :a)))
我可以通过以下方式收到错误消息:
(into (transient []) (repeat 10 :a))
;; => ClassCastException clojure.lang.PersistentVector$TransientVector cannot be cast to clojure.lang.IPersistentCollection clojure.core/conj--6410 (core.clj:82)
尝试使用repeat
是不是错了? (没有这样的函数repeat!
)。什么是更好的方法?
答案 0 :(得分:6)
function STRtoArray(str) {
var lines = str.split('\n'),
keys = lines[0].trim().split(','); // getting key fields
var result = lines.slice(1).map(function (l){
return l.trim().split(',').reduce(function (r, l, i) {
if (i === 1) l = Number(l); // casting 'Age' field to number type
if (i === 3) l = Boolean(l === 'true'? 1:0);
r[keys[i]] = l;
return r;
}, {});
});
return result;
}
var str = 'Name,Age,Car,wife \n John,25,,true\n Ben,31,wolksvagen,false'
console.log(STRtoArray(str));
会尽可能自动使用瞬变。
也就是说,into
做的第一件事就是检查它的第一个参数是否有一个瞬态版本(它是否实现了`clojure.lang.IEditableCollection):
如果确实如此,则into
使用into
+ transient
+ reduce
+ conj!
(除此之外,persistent
}} with-meta
保存元数据);
否则使用meta
+ reduce
。
Here's the source as of Clojure 1.8如果您想确认详情。 (特别要注意的是,上述所有情况都适用于采用换能器的三元过载。)
所以你的原始表达式conj
已经使用了瞬态,实际上是这里使用瞬态的最佳方法。任何明确提及(into [] (repeat 10 :a))
/ transient
/等的内容都是多余的。
答案 1 :(得分:1)
你确定这是瓶颈,因为你的原始approch对于这个样本大小来说非常快:
(defn mk-state-prev [value width height]
(vec (repeat height (vec (repeat width value)))))
(time (doall (mk-state-prev 3 1000 1000)))
"Elapsed time: 0.284245 msecs"
(time (get-in (mk-state-prev 3 1000 1000) [100 101] :not-found))
"Elapsed time: 0.305037 msecs"
3 ; found `3`
这引出了下一个问题:
你是如何测量“时间”的?
关于你的mk-state
- 这是我厌倦的一种方法,但它更慢
(defn mk-state [value width height]
(let [v (transient (vector))
row (vec (repeat height value))] ; only create 1 row
(doseq [n (range 0 width)]
(conj! v row)) ; mutate (add rows)
(persistent! v)))
(set! *print-length* 5)
; otherwise the repl will propably hang with printing 1e6 items
(time (doall (mk-state :t 1000 1000)))
"Elapsed time: 1.366543 msecs"
EDIT2:
@birdspider你不能把你的瞬态砸到这样的地方。检查返回值,这是不正确的。 - ClojureMostly 16小时前
这怎么不对?不是咆哮 - 请教育我:)
Clojure 1.8.0
(defn mk-state [value width height]
(let [v (transient (vector))
row (vec (repeat height value))] ; only create 1 row
(doseq [n (range 0 width)]
(conj! v row)) ; mutate (add rows)
(persistent! v)))
#'user/mk-state
user=> (get-in (mk-state :t 1000 1000) [99 99])
:t
user=> (pprint (mk-state :t 10 10))
[[:t :t :t :t :t :t :t :t :t :t]
[:t :t :t :t :t :t :t :t :t :t]
[:t :t :t :t :t :t :t :t :t :t]
[:t :t :t :t :t :t :t :t :t :t]
[:t :t :t :t :t :t :t :t :t :t]
[:t :t :t :t :t :t :t :t :t :t]
[:t :t :t :t :t :t :t :t :t :t]
[:t :t :t :t :t :t :t :t :t :t]
[:t :t :t :t :t :t :t :t :t :t]
[:t :t :t :t :t :t :t :t :t :t]]
nil
答案 2 :(得分:0)
into
函数在内部使用conj
。对于瞬态,您需要使用conj!
函数。例如:
(defn transient-range [limit]
(loop [cnt 0
cum (transient []) ]
(if (< cnt limit)
(recur (inc cnt) (conj! cum cnt))
(persistent! cum))))
(println (transient-range 20))
;=> [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
对于瞬态repeat
,请执行以下操作:
(defn transient-repeat [qty value]
(loop [cnt 0
cum (transient []) ]
(if (< cnt qty)
(recur (inc cnt) (conj! cum value))
(persistent! cum))))
(println (transient-repeat 5 42))
;=> [42 42 42 42 42]