Почему там столько функций конструкции карты в clojure?

Вопрос о новичке, но я действительно не понимаю, почему существует столько операций для построения карт в clojure.

Вы имеете conj, assoc и merge, но они, кажется, более или менее делают то же самое?

(assoc {:a 1 :b 2} :c 3)
(conj {:a 1 :b 2} {:c 3})
(merge {:a 1 :b 2} {:c 3})

Каково действительно различие и почему все эти методы требуются, когда они делают более или менее то же самое?

47
задан amalloy 14 March 2011 в 06:02
поделиться

3 ответа

assoc и conc ведут себя по-разному для других структур данных:

user=> (assoc [1 2 3 4] 1 5)
[1 5 3 4]
user=> (conj [1 2 3 4] 1 5)
[1 2 3 4 1 5]

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

Рассматривать слияние как функцию только для карт (аналогично конъюнкту для других коллекций).

Мое мнение:

  • assoc - используйте, когда вы «меняете» существующие пары ключ / значение
  • con - используйте, когда вы «добавляете» новые пары ключ / значение
  • слияние - используйте при объединении двух или более карт
52
ответ дан 26 November 2019 в 19:43
поделиться

На самом деле эти функции ведут себя совершенно по-разному при использовании с картами.

  1. conj:

    Во-первых, пример (conj {:a 1 :b 2} :c 3) из текста вопроса вообще не работает (ни с 1.1, ни с 1.2; IllegalArgumentException выбрасывается). Существует всего несколько типов, которые можно соединитьс картами, а именно двухэлементные векторы, clojure.lang.MapEntryы (которые в основном эквивалентны двухэлементным векторам) и карты.

    Обратите внимание, что seq карты состоит из множества MapEntrys. Таким образом, вы можете сделать, например,

    (into a-map (filter a-predicate another-map))
    

    (обратите внимание, что into использует conj -- или conj! , когда это возможно -- внутренне). Ни merge, ни assoc не позволяют этого сделать.

  2. merge:

    Это почти точно эквивалентно conj, но заменяет аргументы nil на {} -- пустые хэш-карты -- и, таким образом, возвращает карту, когда первая "карта" в цепочке оказывается nil.

    (apply conj [nil {:a 1} {:b 2}])
    ; => ({:b 2} {:a 1}) ; clojure.lang.PersistentList
    (apply merge [nil {:a 1} {:b 2}])
    ; => {:a 1 :b 2} ; clojure.lang.PersistentArrayMap
    

    Обратите внимание, что ничто (кроме docstring...) не мешает программисту использовать merge с другими типами коллекций. Если это сделать, возникнут странности; не рекомендуется.

  3. assoc:

    Опять же, пример из текста вопроса - (assoc {:a 1 :b 2} {:c 3}) - не сработает; вместо этого будет выброшен IllegalArgumentException. assoc принимает аргумент map, за которым следует четное количество аргументов - те, которые находятся в нечетных позициях (допустим, map находится в позиции 0), являются ключами, те, которые находятся в четных позициях, являются значениями. Я нахожу, что assoc на карты чаще, чем conj, хотя когда я conj, assoc будет казаться громоздким. ;-)

  4. merge-with:

    Для полноты картины, это последняя базовая функция, работающая с картами. Я нахожу ее чрезвычайно полезной. Она работает так, как указано в docstring; вот пример:

    (merge-with + {:a 1} {:a 3} {:a 5})
    ; => {:a 9}
    

    Обратите внимание, что если карта содержит "новый" ключ, который не встречался ни в одной из карт слева от нее, функция слияния не будет вызвана. Это иногда расстраивает, но в 1.2 умный reify может предоставить карту с не nil "значениями по умолчанию".

23
ответ дан 26 November 2019 в 19:43
поделиться

Поскольку карты являются такой вездесущей структурой данных в Clojure, имеет смысл иметь несколько инструментов для работы с ними. Все различные функции синтаксически удобны в немного разных обстоятельствах.

Мой личный взгляд на конкретные функции, которые вы упомянули:

  • Я использую assoc для добавления одного значения в карту, заданную ключом и значением
  • Я использую merge для объединения двух карт или добавления нескольких новых записей одновременно
  • Я обычно не использую conj с картами вообще, поскольку мысленно ассоциирую ее со списками
6
ответ дан 26 November 2019 в 19:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: