Что такое идиоматический способ объединить (или получить объединение) двух списков (или последовательностей) в Clojure?
(merge l1 l2)
не похоже на решение:
a=> (merge '(1 2 3) '(2 3 4))
((2 3 4) 1 2 3)
Что такое идиоматический способ объединить (или получить объединение) двух списков (или последовательностей) в Clojure?
(merge l1 l2)
не похоже на решение:
a=> (merge '(1 2 3) '(2 3 4))
((2 3 4) 1 2 3)
Я думаю, что решение andih отлично работает. Вот альтернативный способ, потому что эй, почему бы и нет. Он использует concat
и distinct
:
user> (distinct (concat '(1 2 3) '(2 3 4)))
=> (1 2 3 4)
Если вам нужны отдельные несортированные данные (наборы), вам следует использовать структуру данных наборов Clojure вместо векторов или списков. И, как косвенно предположил andih, существует основная библиотека для операций над множествами: http://clojure.github.com/clojure/clojure.set-api.html
(require '[clojure.set :refer [union]])
(union #{1 2 3} #{3 4 5})
=> #{1 2 3 4 5}
Если наборы по какой-то причине вам не нужны, читайте дальше. Будьте осторожны с concat
, когда у вас есть значительный объем данных в ваших последовательностях, и рассмотрите возможность использования into
, который намного лучше оптимизирован как алгоритм слияния векторов. Я не знаю, почему concat не реализован с использованием into (или еще лучше — почему concat вообще существует? Кстати, хотя into значительно быстрее, чем concat, он все же намного медленнее, чем conj. RRB-деревья Bagwell, совместимые с обоими Clojure и Scala решат эту проблему, но еще не реализованы для Clojure).
Чтобы перефразировать неустановленное решение Омри с точки зрения «в»:
(distinct (into [1 2 3] [3 4 5]))
=> (1 2 3 4 5)
(into foo bar)
аналогичен (reduce conj foo bar)
, за исключением того, что он будет использовать транзиенты, если они доступны.
- person Philip Potter; 01.10.2012
concat
не может быть постоянным временем для всех входов? Должно быть линейное время по мере роста размера входных данных?
- person Petrus Theron; 03.03.2014
concat
ленив, так что да, это может быть постоянное время, потому что на самом деле это не так уж много работает. он возвращает что-то, что при использовании в качестве последовательности сначала извлекает элементы из первого аргумента, а затем из второго, когда первый исчерпан.
- person Philip Potter; 15.10.2014
Один из способов получить объединение двух списков — использовать union
Clojure> (into #{} (clojure.set/union '(1,2,3) '(3,4,5)))
#{1 2 3 4 5}
или если вы хотите получить список
(into '() (into #{} (clojure.set/union '(1,2,3) '(3,4,5))))
(5 4 3 2 1)
union
работает с аргументами списка. Все, что он делает, это (reduce conj '(1,2,3) '(3,4,5))
. clojure.set
предназначены для работы с заданными аргументами.
- person Marko Topolnik; 30.09.2012
Если вы не возражаете против дубликатов, вы можете попробовать concat:
(concat '(1 2 3 ) '(4 5 6 1) '(2 3))
;;==> (1 2 3 4 5 6 1 2 3)
Одним из вариантов является сведение:
(def colls '((1 2 3) (2 3 4)))
(flatten colls) ;; => (1 2 3 2 3 4)
(distinct (flatten colls)) ;; => (1 2 3 4)
Одна вещь, о которой следует знать, это то, что он будет сглаживать глубоко вложенные коллекции:
(flatten [[1 2 [3 4 5]] [1 [2 [3 4]]]]) ;; => (1 2 3 4 5 1 2 3 4)
Но хорошо работает для карт:
(flatten [[{} {} {}] [{} {} {}]]) ;; => ({} {} {} {} {} {})
merge
уже занятоclojure.core
. Чтобы избежать путаницы, вы можете выбрать другое имя для вашейmerge
функции. См. clojuredocs.org/clojure_core/clojure.core/merge. - person tnoda   schedule 30.09.2012