2015-09-21 83 views
3

這幾乎是我最後一個問題(Clojure idiomatic way to update multiple values of map)的後續,但不完全相同。 (請記住,我是相當新的Clojure的和一致好評函數式語言)Clojure:遍歷套圖

假設我有以下數據結構,定義爲地圖上套:

(def m1 {:1 #{2} :2 #{1 3} :3 #{1}}) 

和地圖的地圖這樣的:

(def m2 {:1 {:1 0 :2 12 :3 23} :2 {:1 23 :2 0 :3 4} :3 {:1 2 :2 4 :3 0}}) 

我想要做的就是更新在M1到一定值的對應關係m2的登記。假設我想要的值是x。得到的m2會是這樣的:

{:1 {:1 0 :2 x :3 23} :2 {:1 x :2 0 :3 x} :3 {:1 x :2 4 :3 0}} 

假設v包含我的地圖每一個可能的密鑰,Y的第一次嘗試,(我悲慘地失敗了),就是做這樣的事情:(假設x=1

(for [i v] 
reduce (fn [m j] (assoc-in m [i j] 1)) d (i m1))) 

不用說,這是失敗的。那麼,如何做到這一點的習慣的方法?

回答

3

據我瞭解你的需求,你要

  1. m1生產一些關鍵的序列。
  2. m2將這些鍵序列中的每一個與特定的常數值相關聯。

第一步是一個相當簡單的轉換m1。我們想要爲每個條目生成0個或更多的密鑰序列(取決於它的集合中有多少個),所以對我來說自然而然的是mapcat。它代表map -then- concat,對於這樣一種情況來說非常好,即從seq的每個元素中我們生成0個或更多我們想要的元素。

(defn key-seqs [coll] 
    (mapcat 
    (fn [[k v]] 
    (map (partial vector k) v)) 
    coll)) 

(key-seqs m1) 
;;=> ([:1 2] [:2 1] [:2 3] [:3 1]) 

。注意,通過mapcat採取的功能本身是map,使得它產生一個序列(可能是空的),用於mapcat解開。但是,這正在返回存儲在這些集合中的多個自己。如果我們想要把它們變成關鍵字匹配m2我們需要多一點的處理:

(defn key-seqs [coll] 
    (mapcat 
    (fn [[k v]] 
    (map (comp (partial vector k) keyword str) v)) 
    coll)) 

(key-seqs m1) 
;;=> ([:1 :2] [:2 :1] [:2 :3] [:3 :1]) 

(我們需要使用str因爲keyword不知道該怎麼做多頭關鍵字通常不是數字,而是。具有一些象徵意義的名稱)

然後我們可以修改上一個問題中的update-m一點點,以便它可以將常量值作爲參數並處理不僅具有相同值兩次的鍵序列:

(defn update-m [m x v] 
    (reduce (fn [m' key-seq] 
      (assoc-in m' key-seq x)) ;; accumulate changes 
      m ;; initial-value 
      v)) ;; collection to loop over 

現在我們似乎是在業務:

(update-m m2 1 (key-seqs m1)) 
;;=> {:1 {:1 0, :2 1, :3 23}, :2 {:1 1, :2 0, :3 1}, :3 {:1 1, :2 4, :3 0}} 
+0

如果OP只是使用數字作爲關鍵字開頭,而不是問題中的這些僞數字關鍵字,這會更容易。 – amalloy

+0

您好,先生,太棒了。 只有一個問題:你能否進一步解釋一下這條線的工作原理: '(map(comp(partial vector k)keyword str)v))' 我的意思是,'comp'在這裏做什麼?我知道它構成了部分功能並將其轉換爲關鍵字,但是您能否進一步解釋一下? –

+0

@amalloy如果我這樣做,它會更容易?我的意思是,這種情況下有一個簡單的解決方案嗎? –

1

試試這個(在此,x 100)

(merge-with merge m2 
    (into {} (for [[k v] m1] [k (into {} (for [i v] [(keyword (str i)) 100]))]))) 

編輯:

的想法是這樣的:

  • 轉換M1從{:1 #{2} :2 #{1 3} :3 #{1}}{:1 {:2 x} :2 {:1 x :3 x} :3 {:1 x}}其每一組基本上轉換成地圖,其中關鍵是該集合的值和值常數x。
  • 合併m2和新的m1。

注:有一個假設,m1中的所有密鑰均以m​​2表示。

2

我覺得一個很好的解決辦法是,如果你改變M1的數據結構類似於

(def m1-new [[:1 :2] [:2 :1] [:2 :3] [:3 :1]]) 

那麼你可以reduce過它並使用assoc-in

(reduce (fn [m path] (assoc-in m path my-new-value)) m2 m1-new)