Какова функция выравнивания одноуровневой последовательности в Clojure? Я использую apply concat
пока, но мне интересно, есть ли для него встроенная функция, либо в стандартной библиотеке, либо в clojure -contrib.
Какова функция выравнивания одноуровневой последовательности в Clojure?
Ответ 1
Мой общий выбор - apply concat
. Кроме того, не (for [subcoll coll, item subcoll] item)
- в зависимости от более широкого контекста это может привести к более четкому коду.
Ответ 2
Нет стандартной функции. apply concat
является хорошим решением во многих случаях. Или вы можете эквивалентно использовать mapcat seq
.
Проблема с apply concat
заключается в том, что она терпит неудачу, если на первом уровне есть что-то другое, кроме набора/последовательности:
(apply concat [1 [2 3] [4 [5]]])
=> IllegalArgumentException Don't know how to create ISeq from: java.lang.Long...
Следовательно, вы можете сделать что-то вроде:
(defn flatten-one-level [coll]
(mapcat #(if (sequential? %) % [%]) coll))
(flatten-one-level [1 [2 3] [4 [5]]])
=> (1 2 3 4 [5])
Как более общий момент, отсутствие встроенной функции обычно не мешает вам определять свой собственный: -)
Ответ 3
Я тоже использую apply concat
- я не думаю, что в ядре есть что-то еще.
flatten
- несколько уровней (и определяется через древовидный переход, а не в виде повторного одноуровневого расширения)
см. также Clojure: полу-сглаживание вложенной последовательности, которая имеет flatten-1
из clojure mvc (и это намного сложнее, чем я ожидал).
обновить, чтобы прояснить лень:
user=> (take 3 (apply concat (for [i (range 1e6)] (do (print i) [i]))))
012345678910111213141516171819202122232425262728293031(0 1 2)
вы можете видеть, что он оценивает аргумент 32 раза - это chunking для эффективности, и в противном случае ленивый (он не оценивает весь список). для обсуждения chunking см. комментарии в конце http://isti.bitbucket.org/2012/04/01/pipes-clojure-choco-1.html