Clojure: создание или обновление значений Map в векторе

Я хочу обновить некоторые значения в моем векторе.

Чтобы изменить это:

[{: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}}))
  )
)

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

leetwinski 17.10.2022 16:27

Я мало знаю об этом языке. В основном я хотел создать многомерный массив. Что-то вроде: array[myId] = ['value1' => x, 'value2' => a] array[myId2] = ['value1' => y, 'value2' => b]

Noweh 17.10.2022 16:56

Если :key равно 1, то прибавить внутри :value1 к :values и 200 к :values2? Затем вы заявляете, что хотите что-то создать — похоже, что вы хотите что-то изменить. Было бы очень полезно, если бы вы могли сформулировать проблему так, чтобы она действительно отражала вашу проблему. Трудно дать правильный совет, если вопрос не ясно показывает вашу проблему.

cfrick 17.10.2022 17:26

Также никогда def кроме как на уровне ns. Судя по вашим попыткам, вы предполагаете, что myvector - это глобальная переменная, которую вы можете заменить в своей функции. Clojure работает не так. Clojure использует неизменяемые данные и хочет, чтобы вы писали в функциональном стиле. Напишите функцию, которая принимает данные в качестве входных данных, извлекает результат из этих данных и возвращает результат.

cfrick 17.10.2022 17:34
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
72
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Если все, что вы хотите сделать, это изменить второй элемент (карту) в вашем векторе в соответствии с вашими примерами до/после, вы можете сделать что-то вроде этого:

(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))

ABeltramo 17.10.2022 17:06

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

ABeltramo 17.10.2022 17:10

Верно на обоих счетах. Я выбрал update, так как я думаю, что это немного более надежно, поскольку это не нарушит шаблон, если целевая карта в какой-то момент в будущем будет иметь дополнительные пары ключ/значение. И да, я согласен, обновление вектора по индексу ненадежно.

Matias Bjarland 17.10.2022 17:29

Я выбрал merge... то, что я получаю, печатая текст на телефоне.

Matias Bjarland 18.10.2022 10:21

Непонятно, какова ваша цель, но я попытался придумать что-то достаточно общее:

(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)

Noweh 17.10.2022 17:05

Не беспокойтесь, я думаю, что тогда нет необходимости использовать карту карт; вы можете: [{:value1 1 :value2 100} {:value1 5, :value2 300}] Тогда вы можете (assoc-in data [1 :value1] 6) что красиво и чисто!

ABeltramo 17.10.2022 17:09
Ответ принят как подходящий

Это будет работать:

(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}}

Другие вопросы по теме