Объедините и проведите вычисление двух векторов, верните карту Clojure
Получилось два вектора. [обувь молочная обувь] и [1 3 1] и карта, которую я хочу получить, - {обувь 2, молоко 3}. Я пытаюсь нанести zipmap на два вектора, и показывает только {обувь 1 молоко 3}. Есть ли другой способ сделать это без цикла и итерации?
3 ответа
Вы также можете использовать для этого немного другое решение, генерируя карты с одной записью для пары элемент-сумма, а затем объединяя их с +
:
(let [goods '[shoes milk shoes]
amounts [1 3 1]]
(apply merge-with + (map hash-map goods amounts)))
;;=> {milk 3, shoes 2}
Вы можете сделать это с помощью reduce
:
- создавать кортежи ключ / значение из двух ваших списков
- накапливать в карту: добавить значение к значению ключа в карте (или начать с 0, если отсутствует (передается ноль))
(let [v1 '[shoes milk shoes]
v2 [1 3 1]]
(reduce
(fn [m [k v]]
(update m k (fnil + 0) v))
{}
(map vector v1 v2)))
; → {shoes 2, milk 3}
Мне очень понравилось решение @leetwinski.
Собственно, для решения подобных проблем в будущем я бы предложил сначала собрать значения всех ключей в списках - в порядке их появления:
(defn vecs2hash
[keys values]
(apply merge-with concat (map (fn [k v] {k (list v)}) keys values)))
Потом:
(def hm (vecs2hash '[shoes milk shoes milk] [1 4 2 3]))
hm
;; => {milk (4 3), shoes (1 2)}
Затем можно было бы написать функцию, работающую с каждым из собранных элементов по вашему желанию.
Определите новую функцию для суммирования всех значений в списке:
(defn sum-up-value
[val]
(apply + val))
Определите вспомогательную функцию, чтобы применить вспомогательную функцию для обработки всех списков значений:
(defn apply-to-each-value
[fun hm]
(apply hash-map (interleave (keys hm) (map fun (vals hm)))))
Итак, в вашем случае:
(apply-to-each-value sum-up-values hm)
;; {milk 7, shoes 3}