Clojure:半嵌套的序列
我有一个embedded列表的向量列表,如下所示:
(([1 2]) ([3 4] [5 6]) ([7 8]))
我所知道的并不理想。 我想把它弄平([1 2] [3 4] [5 6] [7 8])
。
压平不起作用:它给我(1 2 3 4 5 6 7 8)
。
我该怎么做呢? 我想我需要创build一个新的列表基于每个列表项的内容 ,而不是项目,这是我无法find如何从文档做的一部分。
如果你只想把它变平,你可以使用concat
(apply concat '(([1 2]) ([3 4] [5 6]) ([7 8]))) => ([1 2] [3 4] [5 6] [7 8])
要将列表列表转换为包含每个子列表元素的单个列表,您需要按照nickik的build议apply concat
。
但是,通常有一个更好的解决scheme:不要生成列表的列表! 例如,让我们想象一下你有一个名为get-names-for
的函数get-names-for
它需要一个符号,并返回所有可以调用该符号的很酷东西的列表:
(get-names-for '+) => (plus add cross junction)
如果你想获得一些符号列表的所有名字,你可以试试
(map get-names-for '[+ /]) => ((plus add cross junction) (slash divide stroke))
但是这会导致你遇到的问题。 你可以用一个apply concat
粘在一起,但更好的办法是使用mapcat
而不是map
来开始:
(mapcat get-names-for '[+ /]) => (plus add cross junction slash divide stroke)
flatten
代码相当短:
(defn flatten [x] (filter (complement sequential?) (rest (tree-seq sequential? seq x))))
它使用tree-seq
遍历数据结构并返回一系列primefaces。 既然我们想要所有的底层序列,我们可以像这样修改它:
(defn almost-flatten [x] (filter #(and (sequential? %) (not-any? sequential? %)) (rest (tree-seq #(and (sequential? %) (some sequential? %)) seq x))))
所以我们返回所有不包含序列的序列。
你也可能会发现有用的这个通用的1级扁平函数,我发现clojuremvc :
(defn flatten-1 "Flattens only the first level of a given sequence, eg [[1 2][3]] becomes [1 2 3], but [[1 [2]] [3]] becomes [1 [2] 3]." [seq] (if (or (not (seqable? seq)) (nil? seq)) seq ; if seq is nil or not a sequence, don't do anything (loop [acc [] [elt & others] seq] (if (nil? elt) acc (recur (if (seqable? elt) (apply conj acc elt) ; if elt is a sequence, add each element of elt (conj acc elt)) ; if elt is not a sequence, add elt itself others)))))
例:
(flatten-1 (([1 2]) ([3 4] [5 6]) ([7 8]))) =>[[1 2] [3 4] [5 6] [7 8]]
concat
exampe确实为你做了工作,但是这个flatten-1
也允许一个集合中的非seq元素 :
(flatten-1 '(1 2 ([3 4] [5 6]) ([7 8]))) =>[1 2 [3 4] [5 6] [7 8]] ;whereas (apply concat '(1 2 ([3 4] [5 6]) ([7 8]))) => java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer
不pipe嵌套是否不均匀,这个函数都会平滑到序列级:
(fn flt [s] (mapcat #(if (every? coll? %) (flt %) (list %)) s))
所以如果你的原始序列是:
'(([1 2]) (([3 4]) ((([5 6])))) ([7 8]))
你仍然会得到相同的结果:
([1 2] [3 4] [5 6] [7 8])