Clojure从数组中获取坐标

时间:2018-04-19 01:44:19

标签: clojure

我无法弄清楚如何在数组中找到一个字符的坐标。

我有一些小的ASCII地图,如下所示:

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

此地图按行分成数组,因此数组如下所示:

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

我要做的是传递一个像P' P'并找出地图中角色的坐标。在这种情况下,P' P'位于坐标(2,3)。

作为一个起点,我尝试使用

找出角色的列
(doseq [m map] (println (clojure.string/index-of m "P")))

这返回了

的输出
nil
2
nil
nil
nil
nil
nil
nil

在这一点上,我现在很困惑,我怎么能回归' 2'以及该行所在的数组索引。

5 个答案:

答案 0 :(得分:2)

一种方法 - 假设你的输入是你所呈现的字符串向量,就像这样:

(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使用从零开始的索引。

您可以将keepidentity

一起使用来缩短这一点
(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....)是多余的,而只需将someidentity一起使用:

(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)))

答案 1 :(得分:1)

(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字符串,搜索每个字符串以查找子字符串,同时跟踪行索引isome->>线程宏将结果(LazySeq)传递给filter,后者会删除nil列的所有元素。由于我们只想要第一个坐标(假设您要搜索的字符只能在地图中存在一次),我们选择第一个元素。如果地图中不存在子字符串,我们将获得nilsome->>将短路,以便返回nil。否则,索引将递增(因为您的坐标是1索引。

或者,您可以线性化地图,在线性地图中找到索引,然后从线性索引计算2d坐标:

(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))))))))

答案 2 :(得分:1)

我更进一步,写了一个函数,找到所有出现的char的坐标。

(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])

答案 3 :(得分:0)

我添加了另一个P字符,以显示如何找到所有这些字符。以下是使用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。我们还假设数据是矩形的(没有参差不齐),并且没有进行任何真正的解决方案需要的错误检查。

答案 4 :(得分:0)

我会选择这样的事情(更广义)

(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)))

与第一个完全相同