2012-02-23 26 views
32

Ben Aleph kullanarak REDIS veri çekiyorum:Clojure: anahtar kelimelere karma-harita anahtar dizeleri dönüştürün?

(apply hash-map @(@r [:hgetall (key-medication id)])) 

sorun bu veri geliyor geri dizeleri ile anahtarlar için, örneğin:

({"name" "Tylenol", "how" "instructions"}) 

ben olmasını gerektiğinde:

({: adı "Tylenol",: nasıl "talimatları})

Ben daha önce aracılığıyla yeni bir haritanın oluşturulması edildi:

{: adı (m "name"),: nasıl (m "nasıl")}

Ama bu büyük bir miktar için verimsizdir anahtarlar.

orada varsa bunu yapan bir fonksiyon? Ya da her döngü var?

(keyword "foo") 
=> :foo 

yüzden bu fonksiyonu kullanarak haritadaki tüm anahtarları dönüştüren sadece bir olgu var:

cevap

40

uygun anahtar kelimeler içine Dizeleri dönüştüren keyword adlı yararlı işlevi yoktur.

Muhtemelen bunun için Strüktür kırıcı bir liste anlama kullanmayı tercih şey gibi: Çok hassas zipmap kullanarak bunu başarabilirsiniz

(into {} 
    (for [[k v] my-map] 
    [(keyword k) v])) 
+0

temel yineleme haritaları için standart bir fonksiyon olup olmadığını kontrol ediyordu, en kolay çözümdür gibi Evet görünüyor. Ama bunu soyutlamak zor değil. Teşekkürler – dMix

+3

Bunu yapacak standart bir işlev (çekirdek libs içinde) var, aşağıda benim cevabım – djhworld

3

:

(defn modify-keys [f m] (zipmap (map f (keys m)) (vals m))) 
(modify-keys keyword {"name" "Tylenol", "how" "instructions"}) 
; {:how "instructions", :name "Tylenol"} 

Temelde, zipmap oluşturmanızı sağlar ayrı ayrı anahtarları ve değerleri belirleyerek bir harita.

+4

aynı sırada olması garantili anahtarlar ve vals vardır? – gtrak

+0

Emin değilim. Nasıl kontrol edeceğimi bilmiyorum. – viebel

+0

http://stackoverflow.com/questions/10772384/clojures-maps-are-keys-and-vals-in-same-order – Inshallah

73

Ayrıca yinelemeli yanı böylece bu haritayı yürüyecek keywordize-keys

(use 'clojure.walk) 
(keywordize-keys {"name" "Tylenol", "how" "instructions"}) 
;=> {:name "Tylenol", :how "instructions"} 

fonksiyonu ile istenilen sonucu elde etmek clojure.walk kütüphanesini kullanabilirsiniz o olacak iç içe harita çok

yılında "keywordize" tuşları http://clojuredocs.org/clojure_core/clojure.walk/keywordize-keys

+2

Bu benim için iç içe geçmiş haritalar için çalışmıyor gibi gözüküyor. –

4

Ben clojure.walk/keywordize-keys ne istediğiniz, djhworld katılıyorum. Bu clojure.walk/keywordize-keys kaynak koduna Bakmak değer

:

(defn keywordize-keys 
    "Recursively transforms all map keys from strings to keywords." 
    [m] 
    (let [f (fn [[k v]] (if (string? k) [(keyword k) v] [k v]))] 
    (clojure.walk/postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m))) 

ters dönüşüm java birlikte çalışma için bazen kullanışlıdır:

(defn stringify-keys 
    "Recursively transforms all map keys from keywords to strings." 
    [m] 
    (let [f (fn [[k v]] (if (keyword? k) [(name k) v] [k v]))] 
    (clojure.walk/postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m))) 
0

Ben ikinci Mikera en into based answer @.Alternatif olarak, değil, en özlü ama başka bir seçenek kullanılarak doç + dissoc/olacağını azaltmak:

(reduce #(dissoc (assoc %1 (keyword %2) (get %1 %2)) %2) my-map (keys may-map)) 
0

Belki de gelen veriler json ise ve clojure.data.json kullanıyorsanız, Hem CSV belirtebilirsiniz dikkati çekiyor key-fn ve dize (docs) ayrıştırma sonuçları manipüle etmek için bir value-fn -

;; Examples from the docs 

(ns example 
    (:require [clojure.data.json :as json])) 


(json/read-str "{\"a\":1,\"b\":2}" :key-fn keyword) 
;;=> {:a 1, :b 2} 

(json/read-str "{\"a\":1,\"b\":2}" :key-fn #(keyword "com.example" %)) 
;;=> {:com.example/a 1, :com.example/b 2}