#clojure
#clojure
Вопрос:
Я спрашивал об особенностях zipmap
construct, чтобы только обнаружить, что я, по-видимому, делал это неправильно. Итак, я узнал о (map vector v u)
в процессе. Но до этого случая я использовал zipmap для выполнения (map vector ...)
работы. Сработало ли это тогда, потому что результирующая карта была достаточно маленькой, чтобы ее можно было отсортировать?
И к актуальному вопросу: в чем польза zipmap
и как / когда ее использовать. И когда использовать (map vector ...)
?
Моя первоначальная проблема требовала первоначального порядка, поэтому сопоставление чего-либо не было бы хорошей идеей. Но в принципе — за исключением порядка результирующих пар — эти два метода эквивалентны, потому что seq
‘общая карта становится последовательностью векторов.
(for [pair (map vector v (rest v))]
( ... )) ;do with (first pair) and (last pair)
(for [pair (zipmap v (rest v))]
( ... )) ;do with (first pair) and (last pair)
Ответ №1:
Используйте (zipmap …), когда вы хотите напрямую создать hashmap из отдельных последовательностей ключей и значений. Результатом является hashmap:
(zipmap [:k1 :k2 :k3] [10 20 40])
=> {:k3 40, :k2 20, :k1 10}
Используйте (map vector …), когда вы пытаетесь объединить несколько последовательностей. На выходе получается ленивая последовательность векторов:
(map vector [1 2 3] [4 5 6] [7 8 9])
=> ([1 4 7] [2 5 8] [3 6 9])
Несколько дополнительных замечаний для рассмотрения:
- Zipmap работает только с двумя входными последовательностями (ключи значения), тогда как map vector может работать с любым количеством входных последовательностей. Если ваши входные последовательности не являются парами ключ-значение, то это, вероятно, хороший намек на то, что вам следует использовать map vector, а не zipmap
- zipmap будет более эффективным и простым, чем создание map vector, а затем последующее создание hashmap из пар ключ / значение — например,
(into {} (map vector [:k1 :k2 :k3] [10 20 40]))
это довольно сложный способ создания zipmap - map vector является ленивым — поэтому он приносит немного дополнительных накладных расходов, но очень полезен в обстоятельствах, когда вам действительно нужна лень (например, при работе с бесконечными последовательностями)
- Вы можете выполнить (seq (zipmap ….)), чтобы получить последовательность пар ключ-значение, подобную (map vector …), однако имейте в виду, что это может изменить порядок следования пар ключ-значение (поскольку промежуточная хэш-карта неупорядочена)
Комментарии:
1. Другое использование
zipmap
, которое я использую постоянно, — это создание карты из вектора карт.. Рассмотрим,(zipmap (map :id data) data)
где данные представляют собой вектор карт, каждая из которых содержит уникальную:id
пару ключ / значение.
Ответ №2:
Методы более или менее эквивалентны. Когда вы используете zipmap, вы получаете карту с парами ключ / значение. Когда вы выполняете итерацию по этой карте, вы получаете векторы [key value]. Однако порядок отображения не определен. С помощью конструкции ‘map’ в вашем первом методе вы создаете список векторов с двумя элементами. Порядок определен.
Zipmap может быть немного менее эффективным в вашем примере. Я бы придерживался ‘map’.
Редактировать: О, и zipmap не ленивый. Итак, еще одна причина не использовать это в вашем примере.
Правка 2: используйте zipmap, когда вам действительно нужна карта, например, для быстрого доступа на основе случайного ключа.
Ответ №3:
Они могут показаться похожими, но на самом деле очень отличаются.
zipmap
создает карту(map vector ...)
создаетLazySeq
из n-кортежей (векторов размером n)
Это две очень разные структуры данных. Хотя ленивая последовательность из двух кортежей может выглядеть похожей на карту, они ведут себя совсем по-другому.
Допустим, мы сопоставляем две коллекции, coll1
и coll2
. Рассмотрим случай, coll1
содержащий повторяющиеся элементы. Вывод zipmap
будет содержать только значение, соответствующее последнему появлению дубликатов ключей в coll1
. Вывод (map vector ...)
будет содержать 2 кортежа со всеми значениями дублирующихся ключей.
Простой пример REPL:
=> (zipmap [:k1 :k2 :k3 :k1] [1 2 3 4])
{:k3 3, :k2 2, :k1 4}
=>(map vector [:k1 :k2 :k3 :k1] [1 2 3 4])
([:k1 1] [:k2 2] [:k3 3] [:k1 4])
Имея это в виду, тривиально видеть опасность в предположении следующего:
Но в принципе — за исключением порядка результирующих пар — эти два метода эквивалентны, потому что последовательная карта становится последовательностью векторов.
Последующая карта становится последовательностью векторов, но не обязательно той же последовательностью векторов, что и результаты из (map vector ...)
Для полноты картины, здесь отсортированы следующие векторы:
=> (sort (seq (zipmap [:k1 :k2 :k3 :k1] [1 2 3 4])))
([:k1 4] [:k2 2] [:k3 3])
=> (sort (seq (map vector [:k1 :k2 :k3 :k1] [1 2 3 4])))
([:k1 1] [:k1 4] [:k2 2] [:k3 3])
Я думаю, что ближе всего мы можем подойти к инструкции, подобной приведенной выше,:
set
Результат (zip map coll1 coll2)
будет равен set
результату (map vector coll1 coll2)
, если coll1
он сам set
.
Это слишком много определителей для двух операций, которые предположительно очень похожи. Вот почему необходимо проявлять особую осторожность при принятии решения, какой из них использовать. Они очень разные, служат разным целям и не должны использоваться взаимозаменяемо.
Ответ №4:
(zipmap k v) принимает две последовательности и возвращает карту (и не сохраняет порядок элементов)
(map vector s1 s2 …) принимает любое количество последовательностей и возвращает seq
используйте первый, когда вы хотите заархивировать две последовательности в карту.
используйте второе, когда вы хотите применить вектор (или список, или любую другую форму для создания последовательности) к нескольким разделениям.
есть некоторое сходство с опцией «сопоставлять» при печати нескольких копий документа 🙂