2012-06-21 15 views
6

Önsöz için, Windows 7'de (64 bit), Java sürüm 6'yı (güncelleme 33) IDE olarak clooj kullanarak çalıştırıyorum. Sorunumu başka bir sistemde yeniden üretmeye çalışmadım. Clojure ile deneyimliyim, ama hiç Java ile değil.İlişkilendirilmiş harita sırasını koruyacak Clojure makro

Çözmeyi denediğim sorunun tamamı tanımlamak için uzun bir süredir, ancak şu anlama geliyor: diyelim ki bir argüman, bir ilişkisel harita alan ve bir vektör döndüren bir makro yapmak istiyorum Haritanın elemanları siparişleri korunur. çalışır, ancak haritaya başka bir öğe eklemek ve sipariş haberci yukarıya

=>(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]] 

Bu neden oluyor bulduğumuza inanıyoruz. PersistentArrayMap olarak adlandırılan 8 veya daha az elemanla ilgili herhangi bir şey gibi görünüyor, ki tam olarak istediğim şey bu, çünkü söyleyebildiğim kadarıyla, bu sınıf düzeni koruyor. Bununla birlikte, 9 veya daha fazla elementi olan bir şey, siparişi tutmayan bir PersistentHashMap olarak başlatılır.

=>(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 

Makromumun herhangi bir boyuttaki ilişkilendirici haritaları alabilmesini isterim, bu bir sorun. Ben liste anlama için tipi ipuçlama, imha bağlama, ve başarı olmadan hepsi ekleme birleştirmeyi denedim. dışarı çekmek için, aşağıdakilerden hiçbiri çalışır:

Ben takdim Bu oyuncak sorunu ile
(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 [email protected])) 

, ben sadece bu yüzden gibi benim makro yazabilirsiniz gerçekleştirmek ve tamamen sorunu önlemek:

=>(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]] 

Ancak, gerçek problemi için çözmeye çalıştığım (ki bunlara girmedim), makronun birleştirici haritalar alabilmesi önemli (her ne kadar% 100 gerekli olmasa da) önemlidir. Herhangi bir şeyin başına gelme şansı bulunmadan önce argümanı PersistentArrayMap'e nasıl çevireceğimi düşünüyorum. Göz önünde bulundurmadığım veya bilmediğim bir çözümün başka bir yolu olabilir.

Bildiğim en iyi şeyi araştırdım ve henüz faydalı bir şey bulamadım. Herhangi bir fikrin/tavsiyenin var mı?

+0

Makro kulübünün ilk kuralı "bir makro yazmama" ... (ikinci sanırım) –

+1

İkinci kuralı hayal ediyorum: "Kes sesini. Cidden, bir makro yazmayın." –

cevap

5

Eğer dizi-harita ile haritanızı yapabilirsiniz

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

veya makroları ilk değil, çünkü yararlıdır bir makro kullanarak önleyebilirsiniz prim olarak daha büyük bir haritada

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]) 

ile

-class ve iyi oluşturmayın * array map

 Note that an array map will only maintain sort order when un-'modified'. 
Subsequent assoc-ing will eventually cause it to 'become' a hash-map.

Kendinizi bir sorted-map ihtiyacın olanı alacak eğer düşünebilir haritalarınızdaki tuşların sırasına bağlı bulursanız. array-map'dan daha iyi ölçeklenecektir.Yukarıdaki örnekte çıktı aynıdır:

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

* Bu benim görüşüm


DÜZENLEME:

bir zaman comparason vs sorted-map ait 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" 
+0

Cevabınız için teşekkür ederiz. Ne yazık ki, makro kulübün ilk kuralına uymamalıyım çünkü değerlendirilmemiş kodu almak için yaptığım "işlev" için zorunludur. Makroları hafifçe almıyorum. Ben zaten dizi-harita fonksiyonunu denedim (aynı zamanda sıralanmış harita), ama sorunumu çözmedim * gerçekten * o zaman benim literal kodum gibi görünecekti (array-map: a 1: b 2 .. vb.) yerine {: a 1: b 2 ... vb.}. Aslında, ben bu işi yapabilirim *, ama sonra makroyu kullanmaya gidersem, zorunlu olarak {} haritalar için kullanamazdım, fakat kullanmak zorunda kalabilirim (dizi haritası vb.) Ve tercih ederim. Bunu önlemek. –

1

Belirtildiği gibi problem çözülemez. Haritalar sipariş vermeyecek şekilde tanımlanmıştır; array-map'da gördüğünüz herhangi bir sipariş rastlantısaldır. Makronuzun bir harita almasını istiyorsanız, istediğiniz bilgileri zaten kaybettiniz.

+1

"Anahtar düzenini koruyan bir haritaya sahip olmak çoğu zaman istenir. Bir dizi harita böyle bir haritadır" http://clojure.org/data_structures#Data%20Structures-ArrayMaps –

+0

Gerekirse, kod dönüşümleri için yararlı olduğu ima ile. Örneğin, {25 (println 25), 26 (println 26), 27 (println 27), 28 (println 28), 29 (println 29), 30 (println 30), 31 (println 31), 32 (println) 32), 33 (println 33), 34 (println 34)} 'bir karma haritası olarak okur ve bu nedenle sözcüklerden farklı bir sırayla basar; Bunun emrini korumak mümkün değildir, dolayısıyla her durumda güvenilmemelidir. – amalloy