在 Clojure 中将嵌套向量减少为另一个向量
Posted
技术标签:
【中文标题】在 Clojure 中将嵌套向量减少为另一个向量【英文标题】:reduce a nested vector to another one in Clojure 【发布时间】:2020-01-02 11:47:15 【问题描述】:在 Clojure 中处理此类内容的惯用方式是什么?
我有:
(def data1
[1 [2 3]])
(def data2
[1 [[2 [3 [4]]]
[22 33]]])
我想得到:
[1 2 3]
和
[[1 2 3 4]
[1 22 33]]
分别。内部向量的嵌套层级可能有不同的长度。
我无法理解此类输入的性质并寻求帮助。基本上,一个函数应该将一个输入(它是一个向量)映射到一个输出(也是一个向量),它本质上是从它的头部到最里面的元素的所有“路线”的一个向量。这是一个模糊的解释,将不胜感激。
【问题讨论】:
输入总是长度为2的向量吗?您的示例中的第二个元素具有不同的结构,一个是数字向量,另一个是向量向量。结构各部分的解释是什么? @Lee,不,输入并不总是长度为 2 的向量。在其平凡的形式中,它可能只是 [1],应该导致 [[1]]。换句话说,输入有 1 个或 2 个元素(其中第 2 个元素是向量或数字)。将输入视为每个向量都是一个分支的树可能会有所帮助。 我认为你已经一针见血了:这对我来说看起来像是深度优先搜索。tree-seq
是以您正在寻找的方式遍历数据结构的惯用方式,但我不清楚您正在寻找什么输出。例如,您希望从中得到什么输出? (def data3 [1 [[2 [3 [4]]] [22 33] 44]])
@柯南,应该是[[1 2 3 4] [1 22 33] [1 44]]
。
【参考方案1】:
(defn transform [v]
(let [[x & [xs]] v]
(loop [r xs
res []]
(cond
(empty? r) res
(vector? (first r)) (recur (rest r)
(conj res
(into
(conj [] x)
(flatten (first r)))))
:else (into (conj res x) r)))))
(def data1
[1 [2 3]])
(def data2
[1 [[2 [3 [4]]]
[22 33]]])
(def data3
[1 [[20 25 [30 [40 [50]]]]
[2 3 [4 5 [6 7 [8 9]]]]
[[60] 70 [80 [90 100 [110 120 130 [140 150]]]]]]])
; user=> (transform data1)
; [1 2 3]
; user=> (transform data2)
; [[1 2 3 4] [1 22 33]]
; user=> (transform data3)
; [[1 20 25 30 40 50] [1 2 3 4 5 6 7 8 9] [1 60 70 80 90 100 110 120 130 140 150]]
【讨论】:
谢谢。它为输入[1]
提供了错误的输出。它应该是[1]
,而不是[]
。对于输入[[1 [2]]]
,它也会给出错误的输出[]
而不是[1 2]
。
@varnie 你的向量结构是什么?我有点困惑。【参考方案2】:
(defn transform [[f & r]]
(let [rr (apply concat r)]
(if (= (flatten rr) rr)
(vec (cons f rr))
(mapv #(if (vector? %)
(vec (cons f (flatten %)))
[f %])
rr))))
;测试用例
(transform [1 [2 3]]) => [1 2 3]
(transform [1 [[2 [3 [4]]] [22 33]]]) => [[1 2 3 4] [1 22 33]]
(transform [1 [[2 [3 [4]]] [22 33] 44]]) => [[1 2 3 4] [1 22 33] [1 44]
(transform [1]) => [1]
(transform [1 [2]]) => [1 2]
【讨论】:
以上是关于在 Clojure 中将嵌套向量减少为另一个向量的主要内容,如果未能解决你的问题,请参考以下文章