Clojure:半展平嵌套序列
我有一个包含嵌入向量列表的列表,看起来像:Clojure:半展平嵌套序列,clojure,sequence,Clojure,Sequence,我有一个包含嵌入向量列表的列表,看起来像: ([12])([34][56])([78])) 我知道这不是理想的合作方式。我想把它展平到([12][34][56][78]) 展平不起作用:它给了我(12345678) 我该怎么做?我想我需要根据每个列表项的内容创建一个新列表,而不是项目,而这部分我无法从文档中找到如何操作。如果您只想将其展平一级,可以使用concat (apply concat '(([1 2]) ([3 4] [5 6]) ([7 8]))) => ([1 2] [3 4]
([12])([34][56])([78]))
我知道这不是理想的合作方式。我想把它展平到([12][34][56][78])
展平不起作用:它给了我(12345678)
我该怎么做?我想我需要根据每个列表项的内容创建一个新列表,而不是项目,而这部分我无法从文档中找到如何操作。如果您只想将其展平一级,可以使用
concat
(apply concat '(([1 2]) ([3 4] [5 6]) ([7 8])))
=> ([1 2] [3 4] [5 6] [7 8])
要将列表列表转换为包含每个子列表元素的单个列表,您需要像nickik建议的那样
apply-concat
然而,通常有一个更好的解决方案:不要首先生成列表列表!例如,假设您有一个名为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)
flatte
的代码相当短:
(defn flatten
[x]
(filter (complement sequential?)
(rest (tree-seq sequential? seq x))))
它使用tree-seq
遍历数据结构并返回原子序列。因为我们需要所有的底层序列,我们可以这样修改它:
(defn almost-flatten
[x]
(filter #(and (sequential? %) (not-any? sequential? %))
(rest (tree-seq #(and (sequential? %) (some sequential? %)) seq x))))
因此,我们将返回所有不包含序列的序列。此外,您可能会发现我在上找到的这个通用1级展平函数很有用: 例如:
(flatten-1 (([1 2]) ([3 4] [5 6]) ([7 8])))
=>[[1 2] [3 4] [5 6] [7 8]]
concat
exampe当然可以为您完成这项工作,但此flatte-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
无论嵌套是否不均匀,下面的函数都将平滑到序列级别:
(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])
对mapcat来说是+1——这导致了一个比其他方法更优雅的解决方案。很高兴知道。谢谢我使用的是
映射索引
,但是没有mapcat索引
@PostSelf映射索引
只是向映射
添加参数的简写。不要使用(应用concat(映射索引的f xs))
,而是尝试(映射cat f(范围)xs)
@amalloy太棒了!我意识到我根据每对中的第二个元素做了一个过滤器,所以除非有方法合并它,否则我必须将其保留为is@PostSelf当然有mapcat
是一种“基本”列表操作,许多其他操作都可以在其上构建。您可以编写(mapcat(fn[ix](let[x')(when(pred x')[ix'])(range)xs)
(def balls'(:a1)(:b1)(:c1)))
不完全是:(apply concat balls)=>(:a1(:b1)(:c1))完美:(几乎平坦的球)=>(:a1)(:b1(:c 1))
([1 2] [3 4] [5 6] [7 8])