代码之家  ›  专栏  ›  技术社区  ›  David Furnam

Clojure从数组中获取坐标

  •  1
  • David Furnam  · 技术社区  · 6 年前

    我很难找到数组中字符的坐标。

    我有一些小ASCII映射,如下所示:

    +-----+
    |XPX X|
    |X   X|
    |X  XX|
    |X   X|
    |XX DX|
    +-----+
    

    此贴图按直线拆分为一个数组,因此该数组如下所示:

    ["+-----+" "|XPX X|" "|X   X|" "|X  XX|" "|X   X|" "|XX DX|" "+-----+"]
    

    我要做的是传递一个字符,例如“P”,并找出该字符在地图中的坐标。在这种情况下,“P”位于坐标(2,3)处。

    作为起点,我尝试使用

    (doseq [m map] (println (clojure.string/index-of m "P")))
    

    这返回了的输出

    nil
    2
    nil
    nil
    nil
    nil
    nil
    nil
    

    此时,我对如何返回“2”和此行所在的数组索引感到困惑。

    5 回复  |  直到 6 年前
        1
  •  2
  •   Solaxun    6 年前

    一种方法是,假设您的输入是您所呈现的字符串向量,如下所示:

    (def the-map ["+-----+" "|XPX X|" "|X   X|" "|X  XX|" "|X   X|" "|XX DX|" "+-----+"])
    
    (defn get-index [item coll]
      (some #(when ((complement nil?) %) %)
             (map-indexed (fn [ix x] (let [i (clojure.string/index-of x item)]
                                      (when i [ix i])))
                          coll)))
    

    这将返回您要查找的任何项目的第一个实例,例如“+”的实例 [0,0] . (2,3)实际上是(1,2),因为clojure使用基于零的索引。

    您可以使用 keep 具有 identity

    (defn get-index [item coll]
      (first (keep identity
                   (map-indexed (fn [ix x] (let [i (clojure.string/index-of x item)]
                                            (when i [ix i])))
                                coll))))
    

    编辑:

    我意识到 (first (keep identity....) ,而只需使用 some 具有 身份 :

    (defn get-index [item coll]
      (some identity 
            (map-indexed (fn [ix x] (let [i (clojure.string/index-of x item)]
                                         (when i [ix i])))
                                       coll)))
    

    下面的一些答案为您提供了获取每个匹配坐标的方法,而不是第一个坐标。你所要做的就是改变 some identity remove nil? 在我的上述版本中,可以实现这一点。

    例如:

    (defn get-index [item coll]
      (remove nil? 
            (map-indexed (fn [ix x] (let [i (clojure.string/index-of x item)]
                                         (when i [ix i])))
                                       coll)))
    

    最后,如果您真的希望索引是基于一的,那么您可以增加找到的每个索引:

    (defn get-index [item coll]
      (some identity 
            (map-indexed (fn [ix x] (let [i (clojure.string/index-of x item)]
                                         (when i [(inc ix) (inc i)])))
                                       coll)))
    
        2
  •  1
  •   cjg    6 年前
    (def strmap ["+-----+" "|XPX X|" "|X   X|" "|X  XX|" "|X   X|" "|XX DX|" "+-----+"])
    
    (defn find-char-2d
      [arr char-to-find]
      (some->> (map-indexed (fn [i row]
                              [i (clojure.string/index-of row char-to-find)])
                            arr)
               (filter second)
               first
               (map inc)))
    
    (println (find-char-2d strmap "Q")) ; prints "nil"
    (println (find-char-2d strmap "P")) ; prints "(2, 3)"
    

    这个 map-indexed 循环通过 row 字符串,在跟踪行索引的同时搜索每个子字符串 i . 这个 some->> 线程宏传递结果(这是一个 LazySeq )到 filter ,将删除所有元素 nil 柱。因为我们只需要第一个坐标(假设您搜索的角色在地图中只能存在一次),所以我们选择第一个元素。如果子字符串在映射中不存在,我们将得到 ,以及 部分->&燃气轮机; 将短路,以便 已返回。否则,索引都将递增(因为坐标是1索引的)。

    (defn find-char-2d
      [arr char-to-find]
      (some-> (clojure.string/join "" arr)
              (clojure.string/index-of char-to-find)
              ((juxt #(-> (/ % (count arr)) int inc)
                     #(inc (mod % (count (first arr))))))))
    
        3
  •  1
  •   akond    6 年前

    我进一步编写了一个函数,可以查找所有字符的坐标。

    (let [a ["+-----+" "|XPX X|" "|X   X|" "|X  XX|" "|X   X|" "|XX DX|" "+-----+"]]
            (letfn [(find-coords [a ch]
                        (let [op (fn [f] (comp inc #(f % (count (first a)))))]
                            (->> a
                                 (clojure.string/join "")
                                 (map-indexed vector)
                                 (filter (comp (partial = ch) second))
                                 (map first)
                                 (map (juxt (op quot) (op rem))))))]
                (find-coords a \P)))
    
    => ([2 3])
    
    (find-coords a \X)
    => ([2 2] [2 4] [2 6] [3 2] [3 6] [4 2] [4 5] [4 6] [5 2] [5 6] [6 2] [6 3] [6 6])
    
        4
  •  0
  •   Alan Thompson    6 年前

    我又加了一个 P char以显示如何查找所有这些。下面是一个更简单的解决方案,使用 for :

    (defn strs->array [strs] (mapv vec strs))
    
    (def data ["+-----+"
               "|XPX X|"
               "|X   X|"
               "|X  XX|"
               "|X P X|"
               "|XX DX|"
               "+-----+"])
    (def data-array (strs->array data))
    
    (defn find-chars-2 [ch-array tgt-char]
      (let [num-rows (count ch-array)
            num-cols (count (first ch-array))]
        (for [ii (range num-rows)
              jj (range num-cols)
              :let [curr-char (get-in ch-array [ii jj])]
              :when (= tgt-char curr-char)]
          [ii jj])))
    

    结果如下:

    (find-chars-2 data-array \P))  => ([1 2] [4 3])
    

    使用 get-in 假设您有嵌套向量,因此需要 strs->array . 我们还假设数据是矩形的(不是参差不齐的),并且没有进行任何真正的解决方案需要的错误检查。

        5
  •  0
  •   leetwinski    6 年前

    我会选择这样的方式(更广义一点)

    (def field ["+-----+"
                "|XPX X|"
                "|X  ZX|"
                "|X  XX|"
                "|X   X|"
                "|XX DX|"
                "+-----+"])
    
    (defn find-2d [pred field]
      (for [[i line] (map-indexed vector field)
            [j ch] (map-indexed vector line)
            :when (pred ch)]
        [i j ch]))
    
    user> (find-2d #{\P} field)
    ;;=> ([1 2 \P])
    
    user> (find-2d #{\P \Z} field)
    ;;=> ([1 2 \P] [2 4 \Z])
    
    user> (find-2d #{\D \P \Z} field)
    ;;=> ([1 2 \P] [2 4 \Z] [5 4 \D])
    
    user> (find-2d #(Character/isUpperCase %) field)
    ;;=> ([1 1 \X] [1 2 \P] [1 3 \X] [1 5 \X] 
    ;;    [2 1 \X] [2 4 \Z] [2 5 \X] [3 1 \X] 
    ;;    [3 4 \X] [3 5 \X] [4 1 \X] [4 5 \X] 
    ;;    [5 1 \X] [5 2 \X] [5 4 \D] [5 5 \X])
    

    另一个更具功能性(虽然可读性较差)

    (defn find-2d [pred field]
      (filter (comp pred last)
              (mapcat #(map vector (repeat %1) (range) %2)
                      (range)
                      field)))
    

    与第一个完全相同