[英]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以处理下一个元素。
编辑:更新为最快的版本。
(->> (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.