我有一个hashmap:
(def x {:a [1 3] :b [2 4] :c [1 2 3 4]})
我想要反转,因此输入值的每个项目都是输出键,值是连接它的键的串联。 e.g。
{1 [:a :c] 2 [:b :c] 3 [:a :c] 4 [:]}
我有一个解决方案:
(defn invert [input]
(apply merge-with concat
(apply concat
(map (fn [[k vs]]
(map (fn [v] {v [k]}) vs)) input))))
哪个有效:
=> (invert x)
{3 (:a :c), 1 (:a :c), 4 (:b :c), 2 (:b :c)}
但是堆栈溢出的大输入失败了:
=> (def big-x (apply merge (map (fn [i] {i (range 10)}) (range 10000))))
=> (invert big-x)
StackOverflowError clojure.lang.LazySeq.seq (LazySeq.java:49)
如何为大输入完成此操作?
请注意,这与this question类似但不同。
答案 0 :(得分:2)
(defn invert [in]
(reduce (fn [out [key vals]]
(reduce (fn [o v] (assoc o v (conj (get o v []) key)))
out vals))
{} in))
答案 1 :(得分:1)
我的解决方案,似乎有点复杂,但没有溢出:
(defn invert-entry
":a [1 3] => {1 [:a] 3 [:a]}"
[hash-entry]
(reduce #(if (%1 %2)
(update-in %1 [%2] conj)
(merge %1 {%2 [(key hash-entry)]}))
{}
(val hash-entry)))
(defn invert
[x]
(reduce #(let [single-inverted (invert-entry %2)]
(merge-with concat single-inverted %1))
{}
x))
答案 2 :(得分:1)
如果你正在寻找一个简洁的解决方案,并有周期来燃烧......
(defn invert [m]
(apply merge-with into (for [[k vs] m, v vs] {v [k]})))
例如,
(invert x)
;{4 [:c :b], 2 [:c :b], 3 [:a :c], 1 [:a :c]}
我已经忘记了我在哪里看到这个(对于集合,使用merge
代替into
),所以我无法归因于此。这不是我的意思。
我现在意识到,如果我们使用mapcat
重写您的解决方案,并将concat
替换为into
:
(defn invert [input]
(apply merge-with into
(mapcat (fn [[k vs]] (map (fn [v] {v [k]}) vs))
input)))
......它实际上与上述相同。