Как О.П., я разочаровываюсь, пытаясь построить рекурсивные решения с when-let
и if
, next
и last
, и т.д., и т.д. Так что теперь я пытаюсь понять @ntalbs ответа и посмотреть, смогу ли я принять это дальше , изучая документацию Clojure по адресу http://clojuredocs.org/quickref/Clojure%20Core.
Часть # 1 - Замечания:
cons
является функцией списков, в то время как conj
основная функция коллекций, а concat
указана в разделе «Использование (модификация)» последовательностей, но он возвращает ленивую Последовательность. Итак, как эти вещи различаются на практике?
порядок имеет аргумент: вы не можете conj
значение и последовательность, только последовательность и значение. Для cons
это наоборот. concat
выглядит более прощающим.
user=> (type (conj 1 '(2 3 4 5)))
ClassCastException java.lang.Long cannot be cast to clojure.lang.IPersistentCollection clojure.core/conj (core.clj:83)
user=> (type (cons '(2 3 4 5) 1))
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:505)
Три различных типа возврата: Cons, PersistentList или LazySeq
user=> (type (cons 1 '(2 3 4 5)))
clojure.lang.Cons
user=> (type (conj '(2 3 4 5) 1))
clojure.lang.PersistentList
user=> (type (concat 1 '(2 3 4 5)))
clojure.lang.LazySeq
различное поведение для различных типов коллекций:
user=> (cons 3 (sorted-set 5 7 2 7))
(3 2 5 7) ; type = Cons, 3 is just appended to the list,
user=> (conj (sorted-set 5 7 2 7) 3)
#{2 3 5 7} ; type = PersistentTreeSet, with 3 in the correct position.
user=> (concat 3 (sorted-set 5 7 2 7)) ; LazySeq can't be directly returned, so...(order doesn't matter)
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:505)
На мой взгляд, conj
имеет самое простое поведение, поэтому я буду использовать это по предпочтению, если я действительно не хочу ленивой последовательности или конкретно списка.
Часть 2 - @ Рами 'слишком плотный для меня' Понимание решения @ ntalbs.
Вышеприведенное описание предполагает, что conj
является наиболее подходящим методом для добавления вещей в коллекцию, что и делает решение @ ntalbs. Использование для reduce
составляет http://clojuredocs.org/clojure_core/clojure.core/reduce Это эффективный способ применения функции при сборе значений в коллекции.
(reduce f val coll)
Так, reduce
будет применять f
для каждого члена коллекции, начиная с val
. Таким образом, звонок (reduce conj() coll)
берет коллекцию и сначала применяет (conj() (first coll))
. Затем он применяет (conj result (second coll))
и (conj result (third coll))
и т. Д., Где result
является результатом предыдущего шага.
reduce
выглядит как очень мощная команда.
Часть # 3 - еще одно решение
(fn rev [coll]
(into() coll))
Из документации, into
, как представляется, синтаксический сахар для (reduce conj to-coll from-coll)
. Я не уверен, что это элегантно или просто плотно. Тем не менее, он работает с минимальными нажатиями клавиш.
Я не могу заставить это запустить: java.lang.ClassCastException: clojure.lang.PersistentList не может быть отброшен в clojure.lang.IFn – Ramy
@Ramy В вашем исходном коде у вас есть посторонний набор круглых скобок вокруг последнего line: '((cons ...))' -> '(cons ...)'. Убедитесь, что вы разделили их, если вы конвертируете свой код, как указано выше. Копирование моего дословного, я не вижу проблем для тестов 4Clojure. –