Clojure:使用切换键和另一个地图中的值创建地图

时间:2014-07-01 13:52:33

标签: clojure

我正在尝试从输入map创建一种还原索引。我得到的输入地图是:

{"id-1" {"values" ["a" "b" "c"]}, "id-2" {"values" ["a" "b" "c"]}}

然后我希望将其他地图作为结果:

{"a" ["id-1" "id-2"], "b" ["id-1" "id-2"], "c" ["id-1" "id-2"]}

然而,我认为我的思绪确实发疯了,而且我认为自己已经把自己画成了角落而没有开箱即用。这是我到目前为止所得到的,看起来很糟糕:

(->> {"id-1" {"values" ["a" "b" "c"]} "id-2" {"values" ["a" "b" "c"]}}
       (map #(->> (get (second %) "values")
              (map (fn [x y] (hash-map y x)) (into [] (repeat (count (get (second %) "values")) (first %))))
              (apply merge-with concat)))
       (apply merge-with concat))

基本上,我使用第一个map用于"迭代"超过我的所有输入值。然后我使用第二张地图创建一系列单独的地图,如下所示:

({"a" "id-2"} {"b" "id-2"} {"c" "id-2"} {"a" "id-1"} {"b" "id-1"} {"c" "id-1"})

要访问该地图,我使用into [] (repeat ..)创建一个中间数组,以便将值与数组一起提供给地图。

然后我将它们合并在一起以获得我的期望值。

这里有两个问题:

  1. 这看起来要比我直截了当地复杂得多。
  2. 目前的最终结果还不完善,因为我得到了这个:

    {"" (\ i \ d - \ 1 \ i \ d - \ 2)," b" (\ i \ d - \ 1 \ i \ d - \ 2)," c" (\ i \ d - \ 1 \ i \ d - \ 2)}

2 个答案:

答案 0 :(得分:8)

使用map destructuring

(apply merge-with into (for [[k {vs "values"}] input, v vs] {v [k]}))

更明确的

(apply merge-with into
  (for [[k m] input
        v (get m "values")] 
    {v [k]}))

答案 1 :(得分:2)

鉴于此输入:

(def input {"id-1" {"values" ["a" "b" "c"]}, "id-2" {"values" ["a" "b" "c"]}})

更容易做到:

(defn extract [key values]
  (for [v (get values "values")] {v [key]}))

(->> input 
    (mapcat (partial apply extract))
    (apply merge-with concat))

或者,没有附加功能:

(->> (for [[k vs] input]
        (for [v (get vs "values")] {v [k]}))
     (flatten)
     (apply merge-with concat))

以你想要的方式运作。

诀窍是将key包装在extract函数的向量中,这样merge-with concat可以在不连接字符串的情况下工作。