2010-01-01 53 views
16

如何在序列生成操作(如排序)之後將序列轉換回向量?在矢量序列上使用(vec ..)是否昂貴?Clojure:返回序列的序列

一(壞?)可能性正在創造一個新的載體失序:

(vec (sort [1 2 3 4 5 6])) 

我問,因爲我需要隨機訪問(第n。)巨大的排序載體 - 這是現在經過巨大的序列隨機訪問時間很可怕的O(n)

回答

5

從我自己的測試(沒有什麼科學的),你可能會更好地直接在數組中進行排序。但是,如果你排序很少,並且有很多隨機存取功能,那麼使用矢量可能是一個更好的選擇,因爲隨機存取時間平均快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:需要注意的是矢量版本不實際存儲排序向量的任何地方,但不應該顯着改變這一結果,你會使用簡單的綁定在一個循環的速度。

+0

不錯。現在很容易看到,對排序向量執行(vec)比排序直接數組慢4倍!隨機存取時間在向量和陣列中都非常快,以至於我認爲40%並不重要。 – GabiMe 2010-01-02 18:57:57

4

如果您需要對大型向量進行排序的結果進行隨機訪問,那麼通過調用vec所花費的時間應該遠遠超過這樣做的時間節省。

如果你的配置文件發現它太慢了,你可能必須使用java數組。

+0

這就是我現在要做的。調用vec。但我不知道有沒有更好的辦法 – GabiMe 2010-01-02 00:21:21

7

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的集合在大多數情況下)將是可變的, 。如果你不把它交給其他代碼,那很好,但要小心。

+0

應該是java.util.Arrays/sort(他忘了s)。 但是,如果它是一樣的東西,它怎麼快4倍?我在Clojure小組發佈了時間表。 – GabiMe 2010-01-03 08:39:47

+0

至少在一臺服務器虛擬機(你應該使用的)上速度並不快4倍。 c.c.sort使用顯式比較器,並返回一個seq。它也調用數組,而不是數組:前者返回一個對象數組,而後者返回一個類型數組。除了那些使得更一般化的東西外,它是相同的代碼。 這些普遍性成本。 這個練習的全部目的是爲了避免某些工作;這就是爲什麼這個版本更快。 – Rich 2010-01-07 00:07:14

+1

這裏是線程 http://groups.google.com/group/clojure/browse_thread/thread/d5b1152c9647d0fb# – 2010-01-12 15:58:59

-1

作爲一名新的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)

+1

這是誤導。評估REPL中的'(sort [1 2 3 4 5 6])',然後加上'(take-while(partial> 3)* 1)'就可以了。如果您只是採用序列的字符串表示形式,則會丟失類型信息。 – 2016-01-20 18:37:25