在 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 中将嵌套向量减少为另一个向量的主要内容,如果未能解决你的问题,请参考以下文章

包含混合向量和双精度的向量的 Clojure 减少函数

在绑定向量中注释 Clojure

在 Clojure 中将元组数组转换为哈希映射

在 Clojure 中,如何合并两个地图向量?

Clojure:将嵌套矢量格式应用于展平矢量

Clojure 中的可插拔向量处理单元