如何在clojure中转置嵌套向量

时间:2015-03-24 13:15:23

标签: 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中做到这一点?

5 个答案:

答案 0 :(得分:4)

(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个索引处的更新输入fn更新空向量,另外,可以在紧跟最后一个值之后的索引处更新非空向量。

这里的减少是关于将外部累加器传递给内部减少函数,相应地更新它,然后将其返回到外部减少函数,后者又将再次传递到内部rf以处理下一个元素。 / p>

编辑:已更新至最快版本。

答案 1 :(得分:2)

我喜欢ifett's implementation,但使用reduce-kv构建一个可以使用map / mapv轻松构建的向量似乎很奇怪。

所以,我就是这样做的:

(defn transpose [v]
  (mapv (fn [ind]
          (mapv #(get % ind)
                (filter #(contains? % ind) v)))
        (->> (map count v)
             (apply max)
             range)))

答案 2 :(得分:1)

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

请注意,此算法会创建一个懒惰的seqs序列,因此您只需支付实际使用的转换费用。如果您坚持创建向量,请将表单包装在vec中的必要位置 - 或者如果您使用Clojurescript或不介意Clojure 1.7 alpha使用传感器来热切地创建向量无需支付懒惰或不可变性:

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

答案 3 :(得分:0)

我觉得这很容易理解:

(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)组成,即该列的元素序列。

答案 4 :(得分:-1)

(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。如果你真的需要向量,可以在第一个映射之前和它的函数(第一个参数)中添加向量构造函数。

编辑:如果您认为这没用,请发表评论。我们都可以从错误中吸取教训。