2009-09-08 10 views

答えて

24

subvecがおそらく最も良い方法です。 Clojureの文書では、subvecは "O(1)で、非常に高速です。結果のベクトルは元の構造と同じ構造を持ち、トリミングは行われません。"となっています。代わりに、ベクトルを歩いて新しい要素を作成しながら、特定の要素をスキップしてゆくと、速度が遅くなります。

ベクトルの真ん中から要素を取り除くことは、ベクトルが必ずしもうまくいくものではありません。これを頻繁に行う必要がある場合は、dissocを使用できるようにハッシュマップの使用を検討してください。

参照:clojure.github.ioclojuredocs.org

  • subvec

    • subvec、公式サイトのポイントへ。
  • 13
    user=> (def a [1 2 3 4 5]) 
    user=> (time (dotimes [n 100000] (vec (concat (take 2 a) (drop 3 a))))) 
    "Elapsed time: 1185.539413 msecs" 
    user=> (time (dotimes [n 100000] (vec (concat (subvec a 0 2) (subvec a 3 5))))) 
    "Elapsed time: 760.072048 msecs" 
    

    うん - subvecはここ最速

    4

    ですが素敵であることが判明ソリューションのIVです:

    (defn index-exclude [r ex] 
        "Take all indices execpted ex" 
        (filter #(not (ex %)) (range r))) 
    
    
    (defn dissoc-idx [v & ds] 
        (map v (index-exclude (count v) (into #{} ds)))) 
    
    (dissoc-idx [1 2 3] 1 2) 
    
    
    '(1) 
    
    +1

    単一のアイテムを削除するには、これはsubvecを使用するよりも時間がかかりますが、複数のインデックスを削除するにはこれはかなり便利です。 –

    16
    (defn vec-remove 
        "remove elem in coll" 
        [coll pos] 
        (vec (concat (subvec coll 0 pos) (subvec coll (inc pos))))) 
    
    0

    べきは、任意の順序で動作していないためにさらに別の可能性を指数が範囲外だった場合は爆弾...

    (defn drop-index [col idx] 
        (filter identity (map-indexed #(if (not= %1 idx) %2) col))) 
    
    1

    subvecは高速です。トランジェントと組み合わせると、より良い結果が得られます。ベンチマークに判断基準を使用し

    user=> (def len 5) 
    user=> (def v (vec (range 0 5)) 
    user=> (def i (quot len 2)) 
    user=> (def j (inc i)) 
    
    ; using take/drop 
    user=> (bench 
         (vec (concat (take i v) (drop j v)))) 
    ;    Execution time mean : 817,618757 ns 
    ;  Execution time std-deviation : 9,371922 ns 
    
    ; using subvec 
    user=> (bench 
         (vec (concat (subvec v 0 i) (subvec v j len)))) 
    ;    Execution time mean : 604,501041 ns 
    ;  Execution time std-deviation : 8,163552 ns 
    
    ; using subvec and transients 
    user=> (bench 
         (persistent! 
          (reduce conj! (transient (vec (subvec v 0 i))) (subvec v j len)))) 
    ;    Execution time mean : 307,819500 ns 
    ;  Execution time std-deviation : 4,359432 ns 
    

    高速化がより大きい長さであっても大きいです。 len10000に等しい同じベンチは、手段:1,368250 ms,953,565863 µs,314,387437 µsを与える。

    +1

    subvec w/transientsバージョンにはどのようなclojureバージョンを使用しましたか? 'APersistentVector $ SubVectorはIEditableCollection'を実装していないので、4年前には、一時的なものと互換性がないために[オープンバグ](http://dev.clojure.org/jira/browse/CLJ-787)がありました。この例では、clojure 1.7のテストでvec'が 'clojure.lang.APersistentVector $ SubVector'を返しても、' vec(subvec ...) 'にサブベクトル呼び出しをラップしていると仮定しています。以来、おそらく最適化として、私はそれのクロージャーソースに掘っていない。 –

    +0

    1.6。0だと思います。この答えが書かれる数ヶ月前にリリースされました。 – omiel

    +0

    'bench' https://github.com/hugoduncan/criterium –

    2

    ベクターライブラリclojure.core.rrb-vectorは、対数時間連結およびスライシングを提供する。あなたが永続性を必要とし、あなたが求めているものを考慮すれば、対数的な時間解は理論上可能な限り速くなります。特に、クロージャのネイティブsubvecを使用する任意のソリューションよりもはるかに高速です。concatステップは、そのようなソリューションを線形時間に置きます。

    (require '[clojure.core.rrb-vector :as fv]) 
    (let [s (vec [0 1 2 3 4])] 
        (fv/catvec (fv/subvec s 0 2) (fv/subvec s 3 5))) 
    ; => [0 1 3 4] 
    
    関連する問題