我有以下变量
(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中做到这一点?
答案 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。如果你真的需要向量,可以在第一个映射之前和它的函数(第一个参数)中添加向量构造函数。
编辑:如果您认为这没用,请发表评论。我们都可以从错误中吸取教训。