Почему в clojure так много функций построения карты? - PullRequest
47 голосов
/ 08 июля 2010

Вопрос новичка, но я не совсем понимаю, почему существует так много операций для построения карт в 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})

В чем разница, и почему все эти методы необходимы, когда они делают более или менее одно и то же?

Ответы [ 3 ]

51 голосов
/ 08 июля 2010

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

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]

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

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

Мое мнение:

  • assoc - использовать при «изменении» существующих пар ключ / значение
  • Conion - используйте при добавлении новых пар ключ / значение
  • объединить - использовать при объединении двух или более карт
23 голосов
/ 08 июля 2010

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

  1. conj:

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

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

    (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
    

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

  3. assoc:

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

  4. merge-with:

    Ради полноты, это последняя базовая функция, связанная с картами.Я нахожу это чрезвычайно полезным.Это работает, как указывает строка документации;Вот пример:

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

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

6 голосов
/ 08 июля 2010

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

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

  • Я использую assoc , чтобы добавитьодиночное значение для карты с заданным ключом и значением
  • Я использую объединить , чтобы объединить две карты или добавить сразу несколько новых записей
  • Я обычно не использую соединить с картами вообще, поскольку я мысленно связываю это со списками
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...