Я хочу обновить некоторые значения в моем векторе.
Чтобы изменить это:
[{:key 0, :values {:value1 1, :value2 100}} {:key 1, :values {:value1 5, :value2 300}}]
В этом:
[{:key 0, :values {:value1 1, :value2 100}} {:key 1, :values {:value1 6, :value2 500}}]
Я пытаюсь сделать что-то подобное, но безуспешно:
(if (contains? myvectors myId)
(do
(assoc ((myvectors myId) :values) :value2 500));not working
)
(do
(def myvectors (merge myvectors {:key myId :values {:value1 1 :value2 300}}))
)
)
Я мало знаю об этом языке. В основном я хотел создать многомерный массив. Что-то вроде: array[myId] = ['value1' => x, 'value2' => a] array[myId2] = ['value1' => y, 'value2' => b]
Если :key равно 1, то прибавить внутри :value1 к :values и 200 к :values2? Затем вы заявляете, что хотите что-то создать — похоже, что вы хотите что-то изменить. Было бы очень полезно, если бы вы могли сформулировать проблему так, чтобы она действительно отражала вашу проблему. Трудно дать правильный совет, если вопрос не ясно показывает вашу проблему.
Также никогда def кроме как на уровне ns. Судя по вашим попыткам, вы предполагаете, что myvector - это глобальная переменная, которую вы можете заменить в своей функции. Clojure работает не так. Clojure использует неизменяемые данные и хочет, чтобы вы писали в функциональном стиле. Напишите функцию, которая принимает данные в качестве входных данных, извлекает результат из этих данных и возвращает результат.





Если все, что вы хотите сделать, это изменить второй элемент (карту) в вашем векторе в соответствии с вашими примерами до/после, вы можете сделать что-то вроде этого:
(let [m [{:key 0, :values {:value1 1, :value2 100}}
{:key 1, :values {:value1 5, :value2 300}}]]
(update-in m [1 :values] merge {:value1 6 :value2 500}))
=> [{:key 0, :values {:value1 1, :value2 100}} {:key 1, :values {:value1 6, :value2 500}}]
где update-in обновляет второй элемент в векторе (индекс 1 в выражении [1 ...] - индексация на основе 0) и для этого элемента обновляет ключ :values. Для этого значения ({:value1 5, :value2 300}) мы вызываем функцию слияния. update-in отправит старое значение (опять же, старое значение находится в этой точке {:value1 5, :value2 300}) в качестве первого аргумента для merge, а затем мы отправим {:value1 6 :value2 500} в качестве второго аргумента. Поскольку более поздние аргументы merge «победят», значения карты, которые мы отправляем, перезапишут те, которые уже есть в ваших данных.
Для этого конкретного примера я бы назвал assoc вместо merge, поскольку объединять нечего; (update-in m [1 :values] assoc :value1 6 :value2 500))
Это также предполагает, что позиция в векторе равна :key, что в общем случае может быть неверным.
Верно на обоих счетах. Я выбрал update, так как я думаю, что это немного более надежно, поскольку это не нарушит шаблон, если целевая карта в какой-то момент в будущем будет иметь дополнительные пары ключ/значение. И да, я согласен, обновление вектора по индексу ненадежно.
Я выбрал merge... то, что я получаю, печатая текст на телефоне.
Непонятно, какова ваша цель, но я попытался придумать что-то достаточно общее:
(def data [{:key 0, :values {:value1 1, :value2 100}}
{:key 1, :values {:value1 5, :value2 300}}])
(reduce
(fn [v {:keys [key] :as row}]
(conj v
(cond-> row
(= key 1)
(assoc :values {:value1 6, :value2 500}))))
[]
data)
=> [{:key 0, :values {:value1 1, :value2 100}} {:key 1, :values {:value1 6, :value2 500}}]
Это будет reduce над входной последовательностью, изменив заданное row только на основе некоторого condварианта. Поскольку похоже, что вы хотите изменить на основе key, я добавил условие (= key 1), но его можно легко адаптировать к любому условию для всего, что содержится в row.
спасибо за ваш ответ, я попробую это. Я не знаю этого языка, больше привык к PHP. В основном я хотел создать многомерный массив. Что-то вроде: array[myId] = ['value1' => x, 'value2' => a] array[myId2] = ['value1' => y, 'value2' => b], который можно обновлять в зависимости от ключ (MyId1 или MyId2)
Не беспокойтесь, я думаю, что тогда нет необходимости использовать карту карт; вы можете: [{:value1 1 :value2 100} {:value1 5, :value2 300}] Тогда вы можете (assoc-in data [1 :value1] 6) что красиво и чисто!
Это будет работать:
(def v
[{:key 0 :values {:value1 1 :value2 100}} {:key 1 :values {:value1 5, :value2 300}}])
(defn update-values [v k value1 value2]
(mapv (fn [{:keys [key] :as m}]
(cond-> m
(= key k) (assoc :values {:value1 value1 :value2 value2})))
v))
(update-values v 1 6 500)
;; => [{:key 0 :values {:value1 1 :value2 100}}
;; {:key 1 :values {:value1 6 :value2 500}}]
Если возможно, я бы изменил вашу структуру данных, чтобы вы могли лучше использовать основные функции, например карту от ключа к значениям:
(def m
{0 {:value1 1 :value2 100}
1 {:value1 5 :value2 300}})
(assoc m 1 {:value1 6 :value2 500})
;; => {0 {:value1 1 :value2 100}
;; 1 {:value1 6 :value2 500}}
не могли бы вы подробнее рассказать о своей цели. действительно неясно, чего вы пытаетесь достичь.