如何在Clojure中从序列生成对称矩阵?
优雅生成对称矩阵的Clojure方案
嘿,作为Clojure新手能想到过程化实现已经超棒啦!咱们可以利用Clojure的函数式特性和序列操作,写出更简洁优雅的解决方案~
先明确需求:给定对应下三角矩阵(对角线为0)元素的序列,生成一个对称矩阵(满足matrix[i][j] = matrix[j][i],对角线全为0)。
方案一:先构建下三角矩阵,再转置合并
这个思路很直观:先把序列转成下三角矩阵,再和它的转置相加(下三角+上三角刚好得到对称矩阵)。
步骤1:序列转下三角矩阵
首先计算矩阵大小n:下三角非0元素个数是n*(n-1)/2,这里序列长度是10,解得n=5。然后写函数把序列映射为下三角矩阵:
(defn seq-to-lower-tri [s n] (map-indexed (fn [row-idx _] ;; 计算当前行从序列中取的元素起始索引和数量 (let [start-idx (quot (* row-idx (dec row-idx)) 2) take-count row-idx] (vec (concat (take take-count (drop start-idx s)) (repeat (- n take-count) 0))))) (range n)))
测试这个函数:
(seq-to-lower-tri '(9 14 21 23 22 25 32 36 38 42) 5) ;; 输出:[[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]]
步骤2:转置合并生成对称矩阵
下三角矩阵的转置是上三角矩阵,两者相加刚好得到对称矩阵:
(defn lower-tri-to-symmetric [lower-tri] (let [transposed (apply map vector lower-tri)] (mapv (fn [row transposed-row] (mapv + row transposed-row)) lower-tri transposed)))
组合调用就能得到目标矩阵:
(def input-seq '(9 14 21 23 22 25 32 36 38 42)) (def symmetric-matrix (-> input-seq (seq-to-lower-tri 5) lower-tri-to-symmetric))
方案二:直接生成对称矩阵(更简洁)
我们可以跳过中间的下三角矩阵,直接根据行列索引计算每个位置的元素:
- 对角线元素(
i=j)直接设为0 - 当
i>j时,元素等于下三角矩阵中j行i列的值,对应序列索引为j*(j-1)/2 + i - 当
i<j时,元素等于下三角矩阵中i行j列的值,对应序列索引为i*(i-1)/2 + j
实现代码:
(defn seq-to-symmetric [s n] (mapv (fn [i] (mapv (fn [j] (cond (= i j) 0 (> i j) (nth s (+ (* j (dec j)) i)) :else (nth s (+ (* i (dec i)) j)))) (range n))) (range n)))
直接调用即可得到结果:
(seq-to-symmetric '(9 14 21 23 22 25 32 36 38 42) 5) ;; 输出:[[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的风格~
内容的提问来源于stack exchange,提问作者lucascb
相关产品推荐
相关产品推荐

