Clojure 嵌套 for 循环与索引

时间:2021-04-09 23:09:22

标签: clojure clojurescript

我一直在尝试按惯用方式遍历嵌套向量,如下所示:

[[:a 1 :b 1 :c 1] [:a 1 :b 1 :c 3] [:a 1 :b 1 :c 1]]

我还需要在找到值后返回坐标。 例如调用 (find-key-value 3) 应该返回 [1 2]

这是我到目前为止所拥有的,但它没有给我我需要的输出它会返回 ([] [] [] [] [] [1 2] [] [] []),因为我只需要 [1 2]

(defn find-key-value
  [array value]
  (for [x (range 0 (count array))]
    (loop [y   0
           ret []]
      (cond
        (= y (count (nth array x))) [x y]
        :else (if (= value (get-in array [x y]))
                (recur (+ 1 y) (conj ret [x y]))
                (recur (+ 1 y) ret))))))

任何人对我如何修复我的代码以获得我想要的解决方案或有更好的方法有任何想法!

6 个答案:

答案 0 :(得分:3)

列表推导式可用于查找满足谓词的所有值的坐标:

(defn find-locs [pred coll]
  (for [[i vals] (map-indexed vector coll)
        [j val] (map-indexed vector vals)
        :when (pred val)]
    [i j]))

(find-locs #(= 3 %) [[:a 1 :b 1 :c 1] [:a 1 :b 1 :c 3] [:a 1 :b 1 :c 1]])
=> ([1 5])

(find-locs zero? [[0 1 1] [1 1 1] [1 0 1]])
=> ([0 0] [2 1])

提出的问题似乎暗示应该忽略输入中的关键字,在这种情况下,答案变为:

(defn find-locs-ignore-keyword [pred coll]
  (for [[i vals] (map-indexed vector coll)
        [j val] (map-indexed vector (remove keyword? vals))
        :when (pred val)]
    [i j]))

(find-locs-ignore-keyword #(= 3 %) [[:a 1 :b 1 :c 1] [:a 1 :b 1 :c 3] [:a 1 :b 1 :c 1]])
=> ([1 2])

答案 1 :(得分:1)

clojure 核心中有一个函数,它正好适合任务:keep-indexed。这正是indexed map + filter

(defn find-val-idx [v data]
  (ffirst (keep-indexed
           (fn [i row]
             (seq (keep-indexed
                   (fn [j [_ x]] (when (= v x) [i j]))
                   (partition 2 row))))
           data)))

user> (find-val-idx 3 [[:a 1 :b 1 :c 1] [:a 1 :b 1 :c 3] [:a 1 :b 1 :c 1]])
;;=> [1 2]

user> (find-val-idx 10 [[:a 1 :b 1 :c 1] [:a 1 :b 1 :c 3] [:a 1 :b 1 :c 1]])
;;=> nil

user> (find-val-idx 1 [[:a 1 :b 1 :c 1] [:a 1 :b 1 :c 3] [:a 1 :b 1 :c 1]])
;;=> [0 0]

答案 2 :(得分:0)

有一个 map-indexed 有时很有帮助。请参阅 Clojure Cheatsheet 和其他 docs listed here

==>能否请您编辑问题以阐明搜索条件?


以下概述了您可以执行哪些操作来搜索所需的答案:

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

(defn coords
  [data pred]
  (let [result (atom [])]
    (doseq [row (range (count data))
            col (range (count (first data)))]
      (let [elem    (get-in data [row col])
            keeper? (pred elem)]
        (when keeper?
          (swap! result conj [row col]))))
    (deref result)))

(dotest
  (let [data [[11 12 13]
              [21 22 23]
              [31 32 33]]
        ends-in-2? (fn [x] (zero? (mod x 2)))]
    (is= (coords data ends-in-2?)
      [[0 1]
       [1 1]
       [2 1]])))

它基于与文档相同的 template project。有许多变体(例如,您可以使用 reduce 代替原子)。

请查看上面列出的文档。

答案 3 :(得分:0)

(defn vec-to-map [v] (into {} (into [] (map vec (partition 2 v)))))
(defn vec-vals [v] (vals (vec-to-map v)))
(defn map-vec-index [v el] (.indexOf (vec-vals v) el))

(defn find-val-coord
  ([arr val] (find-val-coord arr val 0))
  ([arr val counter]
    (let [row (first arr)
          idx (map-vec-index row val)]
       (cond (< 0 idx) [counter idx]
             :else (recur (rest arr) val (inc counter)))))) 

(find-val-coord arr 3)    ;; => [1 2]

我们也可以编写函数来选择值或对应的键 给出坐标时来自数组:

(defn vec-keys [v] (keys (vec-to-map v)))

(defn get-val-coord [arr coord]
  (nth (vec-vals (nth arr (first coord))) (second coord)))

(defn get-key-coord [arr coord]
  (nth (vec-keys (nth arr (first coord))) (second coord)))


(get-val-coord arr [1 2]) ;; => 3
(get-key-coord arr [1 2]) ;; => :c

答案 4 :(得分:0)

我可能稍微过度设计了这个答案,但这是一种基于 单循环非递归和非惰性方法,适用于任意和混合级别的嵌套并且不会因递归而导致堆栈溢出:

Integer

答案 5 :(得分:0)

一个更简单的解决方案,假设内部向量是二维数组 键值向量,使用二维数组和 .indexOf 的扁平化。

(defn find-coord [arr val]
  (let [m (count (first arr))
        idx (.indexOf (flatten arr) val)]
    [(quot idx m) (quot (dec (mod idx m)) 2)]))
(find-coord arr 3) ;;=> [1 2]