什么是Clojure中的单级序列展平函数?

mis*_*tor 32 functional-programming clojure

什么是Clojure中的单级序列展平函数?我现在正在使用apply concat,但我想知道是否有内置函数,无论是在标准库还是clojure-contrib中.

Mar*_*nik 21

我的首要选择是apply concat.此外,不要忽视(for [subcoll coll, item subcoll] item)- 根据更广泛的背景,这可能会导致更清晰的代码.

更新:鉴于Andrew Cooke的意见,我可能会改变我的第一选择:)

  • mapcat实现为apply concat https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L2652,这是通过处理args作为序列的魔力而懒惰. (3认同)

mik*_*era 15

没有标准功能.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...
Run Code Online (Sandbox Code Playgroud)

因此,您可能想要做以下事情:

(defn flatten-one-level [coll]  
  (mapcat  #(if (sequential? %) % [%]) coll))

(flatten-one-level [1 [2 3] [4 [5]]])
=> (1 2 3 4 [5])
Run Code Online (Sandbox Code Playgroud)

更一般的观点是,缺乏内置函数通常不会阻止您定义自己的函数:-)


and*_*oke 9

我也用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)
Run Code Online (Sandbox Code Playgroud)

你可以看到它对参数进行了32次计算 - 这是效率的分块,否则是懒惰的(它不会评估整个列表).关于分块的讨论,请参阅http://isti.bitbucket.org/2012/04/01/pipes-clojure-choco-1.html末尾的评论