6

はじめに、私は Windows 7 (64 ビット) を使用しており、IDE としてcloojを使用して Java バージョン 6 (アップデート 33) を実行しています。他のシステムで問題を再現しようとはしていません。私は Clojure の経験はありますが、Java の経験はまったくありません。

私が解決しようとしている問題全体を説明すると長くなりますが、要約すると次のようになります。たとえば、1 つの引数、連想マップを取り、その要素のベクトルを返すマクロを作成したいとします。順序が保存されたマップ。

=>(defmacro vectorize-a-map
    [associative-map]
    (vec associative-map))
=>#'ns/vectorize-a-map
=>(vectorize-a-map {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8}
=>[[:a 1] [:b 2] [:c 3] [:d 4] [:e 5] [:f 6] [:g 7] [:h 8]]

それは機能しますが、マップに別の要素を追加すると、順序がめちゃくちゃになります...

=>(vectorize-a-map {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9}
=>[[:a 1] [:c 3] [:b 2] [:f 6] [:g 7] [:d 4] [:e 5] [:i 9] [:h 8]]

なぜこれが起こっているのかを発見したと思います。8 つ以下の要素を持つものはすべて PersistentArrayMap としてインスタンス化されるようです。これはまさに私が望むものです。なぜなら、このクラスは順序を保持しているためです。ただし、9 つ以上の要素を持つものはすべて、順序を保持しない PersistentHashMap としてインスタンス化されます。

=>(type {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8}
=>clojure.lang.PersistentArrayMap
=>(type {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9}
=>clojure.lang.PersistentHashMap

マクロで任意のサイズの連想マップを取得できるようにしたいのですが、これは問題です。リストの理解のために、タイプヒント、バインディングの分解、および引用符を外してスプライシングを試みましたが、すべて成功しませんでした。それを引き出すには、次のいずれも機能しません。

(defmacro vectorize-a-map
  [^clojure.lang.PersistentArrayMap associative-map]
  (vec associative-map))

(defmacro vectorize-a-map
  [[& associative-map]]
  (vec associative-map))

(defmacro vectorize-a-map
  [associative-map]
  (vec
    (for [x associative-map]
      x)))

(defmacro vectorize-a-map
  [associative-map]
  `(vector ~@associative-map))

私が提示したこのおもちゃの問題では、マクロを次のように書くだけで、問題を完全に回避できることがわかりました。

=>(defmacro vectorize-kvs
    [& elements]
    (vec (map vec (partition 2 elements))))
=>#'ns/vectorize-kvs
=>(vectorize-kvs :a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9)
=>[[:a 1] [:b 2] [:c 3] [:d 4] [:e 5] [:f 6] [:g 7] [:h 8] [:i 9]]

しかし、私が解決しようとしている実際の問題 (これには触れていません) では、マクロが連想マップを取得できることが重要です (ただし、100% 必要というわけではありません)。何かが起こる前に引数を PersistentArrayMap にキャストする方法を探しているようです。私が単に考えていない、または認識していない解決策への道が他にあるかもしれません。

私が知っている最善の方法で調査しましたが、まだ役立つものは何も見つかりませんでした. 誰か考えやアドバイスはありますか?

4

2 に答える 2

6

array-map でマップを作成できます

user> (map vec (array-map 1 2 3 4 5 6))
([1 2] [3 4] [5 6])

またはより大きな地図で

user> (map vec (apply array-map (range 50)))
([0 1] [2 3] [4 5] [6 7] [8 9] [10 11] [12 13] [14 15] [16 17] [18 19] [20 21] [22 23] [24 25] [26 27] [28 29] [30 31] [32 33] [34 35] [36 37] [38 39] [40 41] [42 43] [44 45] [46 47] [48 49])

おまけとして、マクロの使用を避けることができます。これは、マクロはファーストクラスではなく、うまく構成できないため便利です*


配列マップ に関するドキュメントからの最初のコメントに関するメモ

配列マップは、「変更」されていない場合にのみソート順を維持することに注意してください。
 その後の関連付けにより、最終的にはハッシュマップになります。

マップ内のキーの順序に依存している場合は、sorted-map必要なものが得られるかどうかを検討することをお勧めします。よりも優れたスケーリングが可能ですarray-map。上記の例では、出力は同じです。

(map vec (apply sorted-map (range 5000)))
[0 1] [2 3] ... [4998 4999]

*これは私の意見


編集:

sorted-mapvsの時間比較array-map

user> (time (dorun (map vec (apply sorted-map (range 500000)))))
"Elapsed time: 391.520491 msecs"
nil
user> (time (dorun (map vec (apply array-map (range 500000)))))
"Elapsed time: 674517.821669 msecs"
于 2012-06-21T01:44:48.180 に答える
1

記載されている問題は解決できません。マップは順序を持たないように定義されています。表示される順序はすべてarray-map偶然です。マクロがマップを受信する必要がある場合は、必要な情報が既に失われています。

于 2012-06-21T09:17:39.087 に答える