将拼接矩阵分成四个季度

the*_*ude 3 clojure matrix

给定一个矩阵作为clojure中的向量向量:

(def A [[1  2  3  4] 
        [5  6  7  8] 
        [9  10 11 12] 
        [13 14 15 16]])
Run Code Online (Sandbox Code Playgroud)

我想把它分成四个季度:

'([[1 2] 
   [5 6]]    ; tl
  [[3 4] 
   [7 8]]    ; tr
  [[9 10]
   [13 14]]  ; bl
  [[11 12] 
   [15 16]]) ;br
Run Code Online (Sandbox Code Playgroud)

这种愚蠢的方法是这样的(受到haskells子矩阵的启发):

(defn submatrix [A slice-col slice-row]
  (let [tl (map (fn [col] (take slice-col col)) (take slice-row A))
        tr (map (fn [col] (take slice-col col)) (drop slice-row A))
        bl (map (fn [col] (drop slice-col col)) (take slice-row A))
        br (map (fn [col] (drop slice-col col)) (drop slice-row A))]
    (vector tl tr bl br))
)
Run Code Online (Sandbox Code Playgroud)

这是有效的(除了它基于列表而不是向量),但在函数式编程方面并不是很漂亮.

另一种方法让clojure感觉更自然,但让我陷入困境:

;; just a helper, simmilar to split-at but returns vectors instead
(defn split-at' [idx v] [(subvec v 0 idx) (subvec v idx)])

(defn mquarter [A]
(let [cuts (map (fn [col] (split-at' 1 col)) A)] ; 1 is just for testing and will be a parameter later ... 
 (prn cuts) ; do something clever here like (map (fn [row] .. take .. drop ..) cuts)
))
Run Code Online (Sandbox Code Playgroud)

如果我称之为它,就像(mquarter [[1 2 3 4] [5 6 7 8] [9 10 11 12] [13 14 15 16]])它给我一样([[1] [2 3 4]] [[5] [6 7 8]] [[9] [10 11 12]] [[13] [14 15 16]]).这很好,但我没有看到如何将切割合并到具有预期结构的新矢量.

是否有一种巧妙的方法切割合并到包含我四个季度的预期结构中?期望的集合具有与输入向量完全不同的结构A,因此我想知道是否甚至可以像这样进行转换 A.

注意:我知道有些库已经在做这个,我想这样做是为了学习clojure.

更新:我对所提出的方法http://git.io/lAZ5OA进行了快速的性能比较,结果如下:

Elapsed time: 9.618612 msecs
Elapsed time: 8294.234684 msecs (is update-in that slow?)
Elapsed time: 4.223093 msecs by a-webb
Elapsed time: 8.166612 msecs
Elapsed time: 0.046654 msecs by andrew-myers (it is executed lazy right!?)
Run Code Online (Sandbox Code Playgroud)

mik*_*era 7

使用core.matrix,该submatrix功能将完全符合您的要求:

(submatrix A 0 2 0 2)
=> #<NDWrapper [[1 2] [5 6]]>
Run Code Online (Sandbox Code Playgroud)

注意:NDWrapper它只是一个轻量级视图对象,可以索引到原始数组中.之所以这样做是因为它的内存效率更高,尽管对于像这样的小型矩阵来说这不太重要.

如果你想把四个季度作为一个序列,只需做类似的事情:

(for [[i j] [[0 0] [0 2] [2 0] [2 2]]] 
  (submatrix A i 2 j 2))
Run Code Online (Sandbox Code Playgroud)


A. *_*ebb 5

你的助手改名为:

(defn vec-split-at [idx v] [(subvec v 0 idx) (subvec v idx)])
Run Code Online (Sandbox Code Playgroud)

使用助手分区矩阵:

(defn partition-matrix-at [m row col] 
  (mapcat (partial apply map vector) 
          (vec-split-at row (mapv (partial vec-split-at col) m))))
Run Code Online (Sandbox Code Playgroud)

A上面的示例:

(partition-matrix-at A 2 2)
 => ([[1 2] 
      [5 6]] 
     [[3 4] 
      [7 8]] 
     [[9 10] 
      [13 14]] 
     [[11 12] 
      [15 16]])
Run Code Online (Sandbox Code Playgroud)