2016-03-07 24 views
2

我在想什麼最習慣的方法來完成以下目標。我剛剛開始使用Clojure,我正在努力尋找操作不依賴於傳統迭代構造的數據結構的策略(for,while等)。在Clojure重組地圖。在當前地圖中創建相應的值到新地圖中

如果我有一個像下面這樣的映射結構:

(def test-map {:cat1-title "Title1", :cat1-val "Value1", :cat2-title "Title2", :cat2-val "Value2"}) 

而且我想將它轉變成以下結構:

{"Title1" "Value1", "Title2" "Value2"} 

從本質上講,我想提出一個新的地圖,它的鍵是*標題鍵的值,和值是相應的*值鍵的值。

這樣做最好的clojure方法是什麼?

我試過的是以下內容(我不知道它是否會一直有效)。它本質上提取*標題值,然後用提取* VAL值

(let [titles 
    (vals (filter #(re-matches #".*-title" 
          (str (key %))) 
       test-map)) 
    values 
    (vals (filter #(re-matches #".*-val" 
          (str (key %))) 
       test-map))] 
    (zipmap titles values)) 

這成功地提取鍵和值拉鍊他們,但我不知道是否有zipmap一起荏苒這是最好的方式,還是最將他們結合起來的慣用方式。

+1

你能發佈一個嘗試,所以我們有更多的東西去? –

+0

大部分問題是我不確定如何處理它,但我可以用我嘗試過的方法進行編輯。 – imcgaunn

+0

是的,即使你不確定去哪裏,看到你到目前爲止嘗試過的東西仍然很好。 –

回答

2

對於較大的地圖,Zipmap將失敗,因爲鍵/值對在地圖內沒有嚴格的排序。對於小地圖,他們通常會按照您創建的順序進行操作,因爲小地圖會創建爲PersistentArrayMaps。大地圖是PersistentHashMap。觀察(apply hash-map (range 100))結果VS (apply hash-map (range 10))所以,如果你有更大的地圖,你-titles將不會與你的-vals

不幸的是,這意味着你真的需要查找明確符合您的標題是瓦爾斯對齊。這是一種方法:

(defn transform [m] 
    (into {} (for [[k v] m 
       :let [title (name k)] 
       :when (.endsWith title "-title") 
       :let [val-name (clojure.string/replace title #"-title$" "-val")]] 
      [v (m (keyword val-name))]))) 

對於標題中的每個關鍵字,查找具有相同前綴的val,並將其全部放入地圖中。

2

我同樣也會回答這個問題提摩太,但對於生產代碼,我認爲這是最好的傳播的事情了一些,並多一點明確:

(ns clj.core 
    (:require [clojure.string :as str]) 
    (:use tupelo.core)) ; it-> 

(defn is-title-kw  [arg] (re-matches #".*-title" (name arg))) 
(defn title-kw->val-kw [arg] (it-> arg 
            (name it) 
            (str/replace it #"-title" "-val") 
            (keyword it))) 

(defn transform [map-arg] 
    (let [title-kws (filter is-title-kw (keys map-arg)) ] 
    (into {} 
     (for [title-kw title-kws] 
     (let [val-kw  (title-kw->val-kw title-kw) 
       title-str (title-kw map-arg) 
       val-str  (val-kw map-arg) ] 
      {title-str val-str}))))) 

和當然,一些單元測試:

(ns tst.clj.core 
    (:use clj.core 
     clojure.test 
     tupelo.core)) 

(def test-map { :cat1-title "Title1", :cat1-val "Value1", 
        :cat2-title "Title2", :cat2-val "Value2" }) 

(deftest t-is-title-kw 
    (is  (is-title-kw :cat1-title)) 
    (is  (is-title-kw :cat2-title)) 
    (is (not (is-title-kw :cat1-val))) 
    (is (not (is-title-kw :cat2-val)))) 

(deftest t-title-kw->val-kw 
    (is (= :cat1-val (title-kw->val-kw :cat1-title))) 
    (is (= :cat2-val (title-kw->val-kw :cat2-title)))) 

(deftest t-transform 
    (is (= (transform test-map) 
      { "Title1" "Value1", 
      "Title2" "Value2" }))) 

運行測試:

~/clj > lein test 

lein test tst.clj.core 

Ran 3 tests containing 7 assertions. 
0 failures, 0 errors. 
1

我寧願使用reduce-kv爲:

(defn transform [items-map] 
    (reduce-kv (fn [result k v] 
       (if-let [[_ name] (re-find #"^:(.+)-title$" (str k))] 
       (assoc result v (items-map (keyword (str name "-val")))) 
       result)) 
      {} items-map)) 
在REPL

user> (def test-map {:cat-1-title "Title1", :cat-1-val "Value1", 
        :cat2-title "Title2", :cat2-val "Value2", 
        :cat3-title "Title3", :cat3-val "Value3"}) 
#'user/test-map 
user> (transform test-map) 
{"Title1" "Value1", "Title2" "Value2", "Title3" "Value3"}