Как объединить список карт в clojure - PullRequest
0 голосов
/ 30 апреля 2018

Мне выдаётся список карт:

({:a 1 :b ["red" "blue"]} {:a 2 :b ["green"]} {:a 1 :b ["yellow"]} {:a 2 :b ["orange"]})

и мне нужно объединить их, чтобы в конечном итоге выглядело так:

({:a 1 :b ["red" "blue" "yellow"]} {:a 2 :b ["green" "orange"]})

Где карты объединяются на основе значения ключа «а». Пока у меня есть это

(->> (sort-by :a)
     (partition-by :a)
     (map (partial apply merge)))

Но слияние перезапишет вектор в "b", а последний даст мне

({:a 1 :b ["yellow"]} {:a 2 :b ["orange"]}) 

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

Вы на самом деле не хотите ничего сортировать или разбивать: это просто время процессора, потраченное ни на что, и в конце вы получаете неуклюжую структуру данных (список карт) вместо чего-то более удобного, карта с ключом "важный" :a значение.

Скорее, я бы написал это как сокращение, где каждый шаг использует merge-with в соответствующем подразделе конечной карты:

(defn combine-by [k ms]
  (reduce (fn [acc m]
            (update acc (get m k) 
                    (partial merge-with into) 
                    (dissoc m k)))
          {}, ms))

после чего у нас

user=> (combine-by :a '({:a 1 :b ["red" "blue"]} 
                        {:a 2 :b ["green"]} 
                        {:a 1 :b ["yellow"]} 
                        {:a 2 :b ["orange"]}))
{1 {:b ["red" "blue" "yellow"]}, 2 {:b ["green" "orange"]}}

, который используется для удобного поиска карты по определенному :a, или, если вы предпочитаете вернуть результаты в виде списка, вы можете легко развернуть его.

0 голосов
/ 30 апреля 2018

Вместо merge используйте merge-with, т.е.

(->> a (sort-by :a) 
       (partition-by :a) 
       (map (partial 
          apply 
          merge-with (fn [x y] (if (= x y) x (into x y))))))

Выходы

({:a 1, :b ["red" "blue" "yellow"]} {:a 2, :b ["green" "orange"]})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...