简体   繁体   English

如何在clojure中获取矩阵中的元素

[英]How to get an element in a matrix in clojure

I have a vector of vectors [[plate,'p1',0,1],[plate,'p2',0,2],[plate,'p3',1,1]] containing x,y positions of detected plates.我有一个向量[[plate,'p1',0,1],[plate,'p2',0,2],[plate,'p3',1,1]]包含检测到的 x,y 位置盘子。

How do I retrieve the x position of plate p3 ?如何检索板p3x位置?

It seems to be a simple task but I'm more familiar with python, so I'm not sure how to do this in clojure.这似乎是一项简单的任务,但我更熟悉 python,所以我不确定如何在 clojure 中执行此操作。

You don't really provide much context on what you're trying to do but it feels like you want to filter the vector of tuples to those that have the symbol p3' in the second position and then return just the third and fourth elements of such a match?您并没有真正提供关于您要做什么的太多上下文,但感觉就像您想将元组向量过滤为那些在第二个位置具有符号p3'的元组,然后只返回第三个和第四个元素这样的比赛?

If so, the following would work:如果是这样,以下将起作用:

dev=> (def plate :plate)
#'dev/plate
dev=> (def data [[plate,'p1',0,1],[plate,'p2',0,2],[plate,'p3',1,1]])
#'dev/data
dev=> (let [[[_ _ x y]] (filter (comp #{'p3'} second) data)]
 #_=>   [x y])
[1 1]

This doesn't feel very idiomatic, so perhaps you could explain more of the context?这感觉不太习惯,所以也许你可以解释更多的上下文?

Note: 'p3' is a symbol whose name is p3' so I wonder if you mean "p3" for a string?注意: 'p3'是一个名称为p3'的符号,所以我想知道你的意思是字符串的"p3"

The vector of vector format doesn't seem very conducive to the sort of access you want to perform - perhaps changing it to a hash map, whose keys are the plate IDs (if that's what p1 , p2 , and p3 are?) would be better to work with?矢量格式的向量似乎不太有利于您要执行的访问类型 - 也许将其更改为哈希映射,其键是板 ID(如果这是p1p2p3是什么?)更好的合作?

i would go with something like this:我会用这样的东西:

(def data [[:plate "p1" 0 1] [:plate "p2" 0 2] [:plate "p3" 1 1]])

(some (fn [[_ v x y]] (when (= v "p3") [x y])) data)
;;=> [1 1]

(some (fn [[_ v x y]] (when (= v "p123") [x y])) data)
;;=> nil
(def p '[[plate,"p1",0,1],[plate,"p2",0,2],[plate,"p3",1,1]])
;; be aware, 'p1' you can use in Python, but because in Clojure `'` at beginning
;; of a symbol is parsed as `quote`, you can't use `''` instead of `""` in contrast to Python.

;; create a nested map out of the vec of vecs
(defn vecs-to-map [vecs]
  (reduce (fn [m [_ id x y]] (assoc m id {:x x :y y}))
          {}
          vecs))
(def m (vecs-to-map p))
;;=> {"p1" {:x 0, :y 1}, "p2" {:x 0, :y 2}, "p3" {:x 1, :y 1}}

;; you can access such a nested list via `get-in` and giving the nested map
;; and the keys it should apply on it.
(get-in m ["p3" :x])
;;=> 1

Since the irregularity that one key is a string and the other a keyword is not so nice, I would make out of them all keywords:由于一个键是字符串而另一个是关键字的不规则性不太好,我会将它们全部提取出来:

(defn vecs-to-map [vecs]
  (reduce (fn [m [_ id x y]] (assoc m (keyword id) {:x x :y y}))
          {}
          vecs))

(def m (vecs-to-map p))

;; access it by:
(get-in m [:p3 :x])
;;=> 1

Additional Thoughts额外的想法

We ignored the first element of the vec plate .我们忽略了 vec plate的第一个元素。 Let's say there exist also another vectors like假设还存在另一个向量,例如

(def b '[[box "b1" 0 1] [box "b2" 0 2] [box "b3" 1 1]])

And if we want a nested map which contains :plate and :box in the outer level as keys, we have to change the vecs-to-map function.如果我们想要一个包含:plate:box作为键的嵌套映射,我们必须更改vecs-to-map函数。

(defn vecs-to-map [vecs]
  (reduce (fn [m [k id x y]] (assoc m (keyword k)
                                    (assoc (get m (keyword k) {})
                                           (keyword id) {:x x :y y})))
          {}
          vecs))

Then we can generate the map containing everything by:然后我们可以通过以下方式生成包含所有内容的地图:

(def m (vecs-to-map (concat p b)))

;; or alternatively in two steps:
;; (def m (vecs-to-map p))
;; (def m (merge m (vecs-to-map b)))


m
;; => {:plate {:p1 {:x 0, :y 1}, :p2 {:x 0, :y 2}, :p3 {:x 1, :y 1}}, :box {:b1 {:x 0, :y 1}, :b2 {:x 0, :y 2}, :b3 {:x 1, :y 1}}}

And we access the content by:我们通过以下方式访问内容:

;; access through:
(get-in m [:plate :p3 :x])
;; => 1

(get-in m [:box :b2 :y])
;; => 2

Here is how I would do it, based on my favorite template project .以下是我将如何做到这一点,基于我最喜欢的模板项目 Please also note that in Clojure strings always use double-quotes like "p1" .另请注意,在 Clojure 中,字符串始终使用双引号,例如"p1" Single quotes are totally different!单引号完全不同!

(ns tst.demo.core
  (:use tupelo.core tupelo.test))

(defn vec-has-label
  "Returns true iff a vector has the indicated label"
  [vec lbl]
  (= lbl (nth vec 1)))

(defn vec->x
  "Given a vector, return the x value"
  [vec]
  (nth vec 2))

(defn find-label
  [matrix label]
  (let [tgt-vecs (filterv #(vec-has-label % label) matrix) ; find all matching vectors
        x-vals   (mapv vec->x tgt-vecs)] ; extract the x values
    x-vals))

The unit tests show the code in action单元测试显示了运行中的代码

(dotest
  (isnt (vec-has-label '[plate "p1" 0 1] "p0"))
  (is   (vec-has-label '[plate "p1" 0 1] "p1"))

  (is= 9 (vec->x '[plate "p1" 9 1]))

  (let [matrix (quote
                 [[plate "p1" 0 1]
                  [plate "p2" 0 2]
                  [plate "p3" 1 1]])]
    (is= (find-label matrix "p3")
      [1])
  ))

The unit test show the 2 ways of "quoting" a data structure that contains one or more symbols.单元测试显示了“引用”包含一个或多个符号的数据结构的两种方式。 This would be unneeded if the redundant plate symbol weren't present.如果不存在冗余plate符号,则不需要此操作。

See also this list of documentation sources .另请参阅此文档来源列表

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM