Поместить элемент в хвост коллекции - PullRequest
48 голосов
/ 20 апреля 2011

Я делаю много:

(concat coll [e]), где coll - это коллекция, а e - один элемент.

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

Ответы [ 4 ]

52 голосов
/ 20 апреля 2011

Некоторые типы коллекций могут дешево добавляться вперед (списки, seq), в то время как другие могут дешево добавляться сзади (векторы, очереди, kinda-sorta lazy-seqs). Вместо использования concat, если возможно, вам следует организовать работу с одним из этих типов (вектор наиболее распространенный) и просто соединиться с ним: (conj [1 2 3] 4) дает [1 2 3 4], тогда как (conj '(1 2 3) 4) дает (4 1 2 3).

14 голосов
/ 20 апреля 2011

concat не добавляет элемент в конец коллекции и не объединяет две коллекции.

concat возвращает последовательность, сделанную из конкатенации двух других последовательностей.Исходный тип коллекций, из которых могут быть выведены seqs, теряется для возвращаемого типа concat.

Теперь коллекции clojure имеют разные свойства, о которых нужно знать для написания эффективного кода, поэтому нетt универсальная функция, доступная в ядре для объединения любых коллекций вместе.Напротив, список и векторы имеют «естественные позиции вставки», которые con знает и делает то, что правильно для вида коллекции.

6 голосов
/ 10 августа 2014

Это очень небольшое дополнение к ответу @ amalloy, чтобы удовлетворить запрос OP на функцию, которая всегда добавляет к хвосту любой коллекции.Это альтернатива (concat coll [x]).Просто создайте векторную версию исходной коллекции:

(defn conj*
  [s x]
  (conj (vec s) x))

Предостережения:

Если вы начали с ленивой последовательности, вы теперь уничтожили лень - т.е. вывод не ленив,Это может быть как хорошо, так и плохо, в зависимости от ваших потребностей.

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

5 голосов
/ 20 апреля 2011

Чтобы извлечь лучшее из того, что Амальлой и Лоран Пети уже сказали: используйте функцию conj .

Одной из замечательных абстракций, которые предоставляет Clojure, является API-интерфейс Sequence API, которыйвключает в себя функцию conj.Если это вообще возможно, ваш код должен быть настолько независимым от типа коллекции, насколько это возможно, вместо этого использовать API seq для обработки операций над коллекциями и выбирать определенный тип коллекции только тогда, когда вам нужно быть конкретным.

Есливекторы хорошо подходят, тогда да, conj будет добавлять элементы в конец.Если вместо этого использовать списки, то conj будет добавлять вещи в начало вашей коллекции.Но если вы затем используете стандартные функции API seq для извлечения элементов из «верха» коллекции (задней части вектора, передней части списка), то не имеет значения, какую реализацию вы используете, потому что она всегда будет использоватьтот, который имеет лучшую производительность и, следовательно, добавляет и удаляет элементы, будет согласованным.

...