code-reviews

2022-08-25T16:03:31.138119Z

I wrote a function that takes a matrix and returns a vector of all the coefficients on the upper diagonals of the matrix, would love to get any feedback. Is there any way to avoid using flatten?

;;      X_11 X_12 X_13
;; X = (X_21 X_22 X_23)
;;      X_31 X_32 X_33

;; X = [X_11 X_22 X_33 X_12 X_23 X_13]

(defn vector-from-symmetric-matrix
  "Given a symmetric matrix, represent it as a vector"
  [X]
  (let [size (count X)
        row (flatten (map range (reverse (range (inc size)))))
        col (flatten (map #(range % size) (range size)))]
    (map (partial get-in X) (partition 2 (interleave row col)))))

2022-08-25T16:08:01.194909Z

if you're only flattening 1 level, you can use mapcat:

user=> (flatten (map range (reverse (range 4))))
(0 1 2 0 1 0)
user=> (mapcat range (reverse (range 4)))
(0 1 2 0 1 0)

2022-08-25T16:08:28.249989Z

oh that's great thank you!

walterl 2022-08-25T17:45:21.894359Z

To support mapcat, beware of flatten: https://stuartsierra.com/2019/09/25/sequences-in-flatland

❤️ 1
walterl 2022-08-25T17:49:07.682959Z

Also, your function will return a lazy seq (from map), and not a vector as the name implies.

2022-08-25T19:11:54.949729Z

Thank you!

2022-08-25T19:15:52.607179Z

what is better, apply vector or into []

2022-08-25T19:16:15.613619Z

mapv if it's the final call

walterl 2022-08-25T19:16:48.095989Z

In cases like that, if mapv won't do (like if your outer fn is mapcat), wrap it in vec.

2022-08-25T19:17:16.390189Z

Thanks, this is what I have now:

(defn vector-from-symmetric-matrix
  "Given a symmetric matrix, represent it as a vector"
  [X]
  (let [size (count X)
        row (mapcat range (reverse (range (inc size))))
        col (mapcat #(range % size) (range size))]
    (mapv (partial get-in X) (partition 2 (interleave row col)))))

2022-08-25T19:17:32.161439Z

that's great, no need for vec or into [] at that point

👍 1
2022-08-25T19:17:55.648179Z

Thanks!

2022-08-25T19:19:16.149169Z

suppose I wanted to assert that X was square, should I use assert for that?

2022-08-25T19:19:45.693659Z

I haven't seen assert used much before

walterl 2022-08-25T19:20:33.745259Z

I just realized that "vector" is ambiguous in this context, so if "vector" in your fn name was meant in the mathematical sense (as it appears to be), returning a different kind of seq isn't necessarily "incorrect". Working with Clojure vectors tend to be simpler and more common, though.

walterl 2022-08-25T19:21:45.932179Z

You can use assert, or add it as a :pre-condition https://clojuredocs.org/clojure.core/defn

walterl 2022-08-25T19:23:07.823969Z

Or, for the Ultimate Power, you can do more thorough checks with https://clojure.org/guides/spec or https://github.com/metosin/malli

2022-08-25T19:41:24.232759Z

Now I have this:

(defn vector-from-symmetric-matrix
  "Given a symmetric matrix, represent it as a vector"
  [X]
  {:pre [(apply = (map count X))            ;; Do the rows all have the same length?
         (= (count X) (count (first X)))]}  ;; does the number of rows match the number of columns?
  (let [size (count X)
        row (mapcat range (reverse (range (inc size))))
        col (mapcat #(range % size) (range size))]
    (mapv (partial get-in X) (partition 2 (interleave row col)))))

⭐ 1