我有一系列整数:
(9 14 21 23 22 25 32 36 38 42)
代表下三角矩阵的值:
| 0| 0| 0| 0| 0|
| 9| 0| 0| 0| 0|
| 14| 21| 0| 0| 0|
| 23| 22| 25| 0| 0|
| 32| 36| 38| 42| 0|
我想基于这个序列创建一个对称矩阵:
(( 0 9 14 23 32)
( 9 0 21 22 36)
(14 21 0 25 38)
(23 22 25 0 42)
(32 36 38 42 0))
由于我对Clojure相对较新,这是我到目前为止所能想到的(这看起来非常程序化):
(defn at
"Equivalent to matrix[i][j]"
[m i j]
(nth (nth m i) j))
(defn group-inf-lines
"Group each values from inferior lines of the matrix"
[values n]
(let [create-line
(fn [line curr i n]
(if (empty? curr)
line
(recur (conj line (take i curr))
(drop i curr)
(inc i)
n)))]
(create-line [] values 1 n)))
(defn create-symmetrical-matrix
"Take a sequence of values and create a symmetrical matrix of size n x n"
[values n]
(let [inf-lines (group-inf-lines values n)]
(for [i (range n)]
(for [j (range n)]
(cond (> i j) (at inf-lines (dec i) j)
(< i j) (at inf-lines (dec j) i)
:else 0)))))
有最多的Clojure-ist方法吗? 也欢迎使用非本机功能的解决方案(例如来自clojure.core.matrix等库)。
答案 0 :(得分:2)
在你的代码中,对于clojure(我猜任何函数式语言)来说真正单调的主要因素是依赖于索引,而任务可以仅使用集合处理来实现。这是我提出的一个解决方案(显然可能会有更多)。
首先,我会根据数据制作三角形集合:
(def data '(9 14 21 23 22 25 32 36 38 42))
(defn triangle [[x & xs :as data]]
(when (seq data)
(butlast
(map first
(reductions (fn [[_ snd] i]
(if (seq snd)
(split-at i snd)
(reduced nil)))
[[x] xs]
(iterate inc 2))))))
user> (triangle data)
;;=> ([9] (14 21) (23 22 25) (32 36 38 42))
第二步是&#34;转置&#34;三角形,制作矩阵的左半部分:
(defn transpose-triangle [triangle]
(->> triangle
(iterate #(filter seq (map rest %)))
(map (partial map first))
(take-while seq)))
user> (transpose-triangle (triangle data))
;;=> ((9 14 23 32) (21 22 36) (25 38) (42))
最后一部分是&#34;胶水&#34;带有它的三角形转置版本:
user> (let [tri (triangle data)
ttri (transpose-triangle tri)]
(map concat
(cons nil tri)
(repeat [0])
(concat ttri [nil])))
;;=> ((0 9 14 23 32)
;; (9 0 21 22 36)
;; (14 21 0 25 38)
;; (23 22 25 0 42)
;; (32 36 38 42 0))
答案 1 :(得分:0)
这实际上是一个非常有趣的算法:
(defn make-triangular [coll]
(let [n-coll (count coll)
n-rows (->> (range) (reductions +) (take-while #(<= % n-coll)) count)
; n-rows x n-rows matrix of zeros, needs to be a vector to support assoc:
zeros (mapv (comp vec repeat) (repeat n-rows n-rows) (repeat n-rows 0))]
(->> coll
(reduce
(fn [[result [row col]] v]
[; assoc v to upper and lower triangles:
(-> result
(assoc-in [row col] v)
(assoc-in [col row] v))
; calculate where the next value should go:
(if (= col (dec row))
[(inc row) 0] ; Approaching the diagonal, drop down by one row and reset to the first col
[row (inc col)])]) ; Not at diagonal yet, stay at the same row and move to the next col
[zeros [1 0]]) ; Starting from a zero matrix, row 1 and col 0
first))) ; Extract the result
我选择使用reduce
和解构来跟踪&#34;州&#34;,即我们正在填写的位置。更多&#34;流导向&#34;可能是更有效的方法,因为这会O(n^2)
与持久性向量相关联。
repeat
中map
的使用感觉有点笨拙,但我发现它在代码高尔夫中很有用。