如何在序列生成操作(如排序)之後將序列轉換回向量?在矢量序列上使用(vec ..)是否昂貴?Clojure:返回序列的序列
一(壞?)可能性正在創造一個新的載體失序:
(vec (sort [1 2 3 4 5 6]))
我問,因爲我需要隨機訪問(第n。)巨大的排序載體 - 這是現在經過巨大的序列隨機訪問時間很可怕的O(n)
如何在序列生成操作(如排序)之後將序列轉換回向量?在矢量序列上使用(vec ..)是否昂貴?Clojure:返回序列的序列
一(壞?)可能性正在創造一個新的載體失序:
(vec (sort [1 2 3 4 5 6]))
我問,因爲我需要隨機訪問(第n。)巨大的排序載體 - 這是現在經過巨大的序列隨機訪問時間很可怕的O(n)
從我自己的測試(沒有什麼科學的),你可能會更好地直接在數組中進行排序。但是,如果你排序很少,並且有很多隨機存取功能,那麼使用矢量可能是一個更好的選擇,因爲隨機存取時間平均快40%以上,但排序性能很糟糕,因爲將矢量轉換爲一個數組,然後回到一個向量。這裏是我的發現:
(def foo (int-array (range 1000)))
(time
(dotimes [_ 10000]
(java.util.Arrays/sort foo)))
; Elapsed time: 652.185436 msecs
(time
(dotimes [_ 10000]
(nth foo (rand-int 1000))))
; Elapsed time: 7.900073 msecs
(def bar (vec (range 1000)))
(time
(dotimes [_ 10000]
(vec (sort bar))))
; Elapsed time: 2810.877103 msecs
(time
(dotimes [_ 10000]
(nth bar (rand-int 1000))))
; Elapsed time: 5.500802 msecs
P.S:需要注意的是矢量版本不實際存儲排序向量的任何地方,但不應該顯着改變這一結果,你會使用簡單的綁定在一個循環的速度。
如果您需要對大型向量進行排序的結果進行隨機訪問,那麼通過調用vec所花費的時間應該遠遠超過這樣做的時間節省。
如果你的配置文件發現它太慢了,你可能必須使用java數組。
這就是我現在要做的。調用vec。但我不知道有沒有更好的辦法 – GabiMe 2010-01-02 00:21:21
Meikel Brandmeyer剛剛在Clojure小組上發佈了一個解決方案。
(defn sorted-vec
[coll]
(let [arr (into-array coll)]
(java.util.Arrays/sort arr)
(vec arr)))
Clojure的sort
返回跨越排序後的數組一個SEQ;這種方法可以做同樣的事情,但是會返回一個向量,而不是seq。
如果你願意,你甚至可以跳過轉換回一個Clojure的持久數據結構:
(defn sorted-arr
"Returns a *mutable* array!"
[coll]
(doto (into-array coll)]
(java.util.Arrays/sort))
,但生成的Java數組(你可以當作一個Clojure的集合在大多數情況下)將是可變的, 。如果你不把它交給其他代碼,那很好,但要小心。
應該是java.util.Arrays/sort(他忘了s)。 但是,如果它是一樣的東西,它怎麼快4倍?我在Clojure小組發佈了時間表。 – GabiMe 2010-01-03 08:39:47
至少在一臺服務器虛擬機(你應該使用的)上速度並不快4倍。 c.c.sort使用顯式比較器,並返回一個seq。它也調用數組,而不是數組:前者返回一個對象數組,而後者返回一個類型數組。除了那些使得更一般化的東西外,它是相同的代碼。 這些普遍性成本。 這個練習的全部目的是爲了避免某些工作;這就是爲什麼這個版本更快。 – Rich 2010-01-07 00:07:14
這裏是線程 http://groups.google.com/group/clojure/browse_thread/thread/d5b1152c9647d0fb# – 2010-01-12 15:58:59
作爲一名新的Clojure開發人員,很容易混淆集合和序列。
此有序向量函數:
(排序[1 2 3 4 5 6]) =>(1 2 3 4 5 6);返回一個序列
但我需要進行下一個操作的載體,因爲這個不工作...
(取而(局部> 3)(1 2 3 4 5 6))
=> ClassCastException java.lang.Long不能轉換爲clojure.lang。IFN用戶/ eval2251(NO_SOURCE_FILE:2136)
讓我們試着序列轉換爲一個矢量:
(VEC(1 2 3 4 5 6))
=> ClassCastException異常java.lang中。長不能投到clojure.lang.IFn用戶/ eval2253(NO_SOURCE_FILE:2139)
不!但如果你把它放在一起,它的工作就很好。
(取而(局部> 3)(排序[1 2 3 4 5 6]))
=>(1 2)
的教訓:不能直接序列工作!它們是這個過程中的一箇中間步驟。 當REPL嘗試計算(1 2 3 4 5 6),它看到AA功能和拋出異常:
(1 2 3 4 5 6) => ClassCastException異常java.lang.Long中不能轉換到clojure.lang.IFn用戶/ eval2263(NO_SOURCE_FILE:2146)
這是誤導。評估REPL中的'(sort [1 2 3 4 5 6])',然後加上'(take-while(partial> 3)* 1)'就可以了。如果您只是採用序列的字符串表示形式,則會丟失類型信息。 – 2016-01-20 18:37:25
不錯。現在很容易看到,對排序向量執行(vec)比排序直接數組慢4倍!隨機存取時間在向量和陣列中都非常快,以至於我認爲40%並不重要。 – GabiMe 2010-01-02 18:57:57