繁体   English   中英

如何在Clojure中转置嵌套向量

[英]How to transpose a nested vector in clojure

我有以下变量

 (def a [[1 2] [3 4] [5 6]])

想要回来

[[1 3 5][2 4 6]]

如果输入为[[1 2] [3 4] [5 6] [7 8 9]]则所需结果为

[[1 3 5 7] [2 4 6 8] [9]]

如何在Clojure中进行操作?

(persistent!
  (reduce
   (fn [acc e]
     (reduce-kv
      (fn [acc2 i2 e2]
        (assoc! acc2 i2 ((fnil conj []) (get acc2 i2) e2)))
      acc
      e))
   (transient [])
   [[1 2 3] [:a :b] [\a] [111] [200 300 400 500]]))

;;=> [[1 :a \a 111 200] [2 :b 300] [3 400] [500]]

可以通过在第0个索引处的update-in fn更新空向量,还可以在紧随最后一个值之后的索引处对非空向量进行更新。

这里的归约是将外部累加器传递给内部归约函数,对其进行相应的更新,然后将其返回给外部归约函数,后者又将再次传递给内部rf以处理下一个元素。

编辑:更新为最快的版本。

我喜欢ifett的实现 ,尽管使用reduce-kv来构建可以使用map / mapv轻松构建的向量似乎很奇怪。

因此,这是我的操作方法:

(defn transpose [v]
  (mapv (fn [ind]
          (mapv #(get % ind)
                (filter #(contains? % ind) v)))
        (->> (map count v)
             (apply max)
             range)))
(->> (range)
     (map (fn [i]
            (->> a
                 (filter #(contains? % i))
                 (map #(nth % i)))))
     (take-while seq))

请注意,此算法创建的是懒惰序列的懒惰序列,因此您只需要为真正消耗的转换付费。 如果您坚持要创建向量,则将表单包装在vec的必要位置-或如果您使用Clojurescript或不介意Clojure 1.7 alpha使用转换器急切地创建向量,而无需支付懒惰或不变性:

(into []
      (comp
       (map (fn [i]
              (into [] (comp (filter #(contains? % i))
                             (map #(nth % i)))
                    a)))
       (take-while seq))
      (range))

我觉得这很容易理解:

(defn nth-column [matrix n]
  (for [row matrix] (nth row n)))

(defn transpose [matrix]
  (for [column (range (count (first matrix)))]
    (nth-column matrix column)))

(transpose a)
=> ((1 3 5) (2 4 6))

nth-column是一个列表推导,根据每个序列(行)的第n个元素生成一个序列。

然后, transpose-matrix仅在列上进行迭代,为每个列创建一个序列元素,该序列元素由(nth-column matrix column)组成,即该(nth-column matrix column)的元素序列。

(map 
    (partial filter identity) ;;remove nil in each sub-list
    (take-while 
        #(some identity %) ;;stop on all nil sub-list
        (for [i (range)] 
            (map #(get % i) a)))) ;; get returns nil on missing values

使用get将丢失的值设为nil,在无限范围内迭代(for),在所有nil子列表上停止,从子列表中删除nil。 如果您确实需要向量,请在第一个地图之前和向量的函数(第一个参数)中添加向量构造函数。

编辑:如果您认为这没有用,请发表评论。 我们都可以从错误中学习。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM