【问题标题】:How do I find the index of an item in a vector?如何在向量中找到项目的索引?
【发布时间】:2011-06-17 09:13:18
【问题描述】:

知道???? 应该是什么吗?有内置的吗? 完成这项任务的最佳方法是什么?

(def v ["one" "two" "three" "two"])

(defn find-thing [ thing vectr ]
  (????))

(find-thing "two" v) ; ? maybe 1, maybe '(1,3), actually probably a lazy-seq

【问题讨论】:

  • Brian's 显然是这个问题的答案,但在下面,cgrand 和 Alex Stoddard 合谋回答了我应该问的问题。
  • 没有什么能阻止您在单独的问题中提出正确的问题 :)

标签: clojure


【解决方案1】:

内置:

user> (def v ["one" "two" "three" "two"])
#'user/v
user> (.indexOf v "two")
1
user> (.indexOf v "foo")
-1

如果您想要所有匹配的索引的惰性序列:

user> (map-indexed vector v)
([0 "one"] [1 "two"] [2 "three"] [3 "two"])
user> (filter #(= "two" (second %)) *1)
([1 "two"] [3 "two"])
user> (map first *1)
(1 3)
user> (map first 
           (filter #(= (second %) "two")
                   (map-indexed vector v)))
(1 3)

【讨论】:

  • 很好,谢谢布赖恩,我的文档搜索器没有找到 indexOf,大概是因为它是 Java。我得继续努力。
  • @John:是的。 indexOf 之前的点表示 Java 互操作。它调用 java.lang.String 中的方法 'indexOf'。 java.lang 默认导入。有关更多示例,请参阅clojure.org/java_interop
  • 调用的是vector的indexOf方法,而不是String的:#<Method public int clojure.lang.APersistentVector.indexOf(java.lang.Object)>
【解决方案2】:

Stuart Halloway 在这篇帖子http://www.mail-archive.com/clojure@googlegroups.com/msg34159.html 中给出了一个非常好的答案。

(use '[clojure.contrib.seq :only (positions)])
(def v ["one" "two" "three" "two"])
(positions #{"two"} v) ; -> (1 3)

如果您想获取第一个值,只需在结果上使用first

(first (positions #{"two"} v)) ; -> 1

编辑:因为clojure.contrib.seq 已经消失,我用一个简单实现的示例更新了我的答案:

(defn positions
  [pred coll]
  (keep-indexed (fn [idx x]
                  (when (pred x)
                    idx))
                coll))

【讨论】:

  • 非常好!这是我所期待的答案。
  • 并不是说它会影响这个答案的优点,但是现在 seq-utils 已经改变了,只是 clojure.contrib.seq。
  • @John,真的,我修好了。谢谢!
  • 在 clojure 1.6 中从哪里获得 clojure.contib.seq?列表中没有库:dev.clojure.org/display/community/Where+Did+Clojure.Contrib+Go
  • @d9k, “如果此处列出了 clojure.contrib 命名空间但没有迁移详细信息,则意味着没有人自愿维护该命名空间。”我为positions 添加了一个示例实现。
【解决方案3】:
(defn find-thing [needle haystack]
  (keep-indexed #(when (= %2 needle) %1) haystack))

但我想警告您不要摆弄索引:通常情况下,它会产生不那么惯用、笨拙的 Clojure。

【讨论】:

  • 哦,好'什么时候'!我一般同意索引,但我有一个 csv 文件,字段的名称在标题中,我想从每一行中获取字段“字段”,所以我正在做的是查找“字段”在标题中,然后是行。我可以想到与交错有关的奇怪事情,但是有没有一种不使用可读的显式索引的好方法?
  • 当我有那个用例时 - csv 标题 - 我刚刚构建了一个地图来进行查找(假设唯一的列标题)。地图 is 然后是我进行索引查找的功能。 (let [header-index (zipmap header-vector (iterate inc 0))] ...)
  • 哇。你回答了我应该问的问题!
  • 好吧,我会提出一些与 Alex 的解决方案非常相似的东西。 (-> "colname" header-index 行) 你有你的价值。
【解决方案4】:

从 Clojure 1.4 开始,clojure.contrib.seq(以及 positions 函数)不可用,因为它缺少维护者: http://dev.clojure.org/display/design/Where+Did+Clojure.Contrib+Go

clojure.contrib.seq/positions 的来源和它的依赖 clojure.contrib.seq/indexed 是:

(defn indexed
  "Returns a lazy sequence of [index, item] pairs, where items come
  from 's' and indexes count up from zero.

  (indexed '(a b c d))  =>  ([0 a] [1 b] [2 c] [3 d])"
  [s]
  (map vector (iterate inc 0) s))

(defn positions
  "Returns a lazy sequence containing the positions at which pred
   is true for items in coll."
  [pred coll]
  (for [[idx elt] (indexed coll) :when (pred elt)] idx))

(positions #{2} [1 2 3 4 1 2 3 4]) => (1 5)

可在此处获取:http://clojuredocs.org/clojure_contrib/clojure.contrib.seq/positions

【讨论】:

  • 感谢发布此版本。从 1.2 开始,您也可以将 (iterate inc 0) 替换为 (range)。
【解决方案5】:

我试图回答我自己的问题,但布赖恩以更好的答案击败了我!

(defn indices-of [f coll]
  (keep-indexed #(if (f %2) %1 nil) coll))

(defn first-index-of [f coll]
  (first (indices-of f coll)))

(defn find-thing [value coll]
  (first-index-of #(= % value) coll))

(find-thing "two" ["one" "two" "three" "two"]) ; 1
(find-thing "two" '("one" "two" "three")) ; 1

;; these answers are a bit silly
(find-thing "two" #{"one" "two" "three"}) ; 1
(find-thing "two" {"one" "two" "two" "three"}) ; nil

【讨论】:

    【解决方案6】:

    这是我的贡献,使用 looping 结构并在失败时返回 nil

    我尽量避免循环,但它似乎适合这个问题。

    (defn index-of [xs x]
      (loop [a (first xs)
             r (rest xs)
             i 0]
        (cond
          (= a x)    i
          (empty? r) nil
          :else      (recur (first r) (rest r) (inc i)))))
    

    【讨论】:

      【解决方案7】:

      我最近不得不多次查找索引,或者我选择了查找索引,因为这比找出解决问题的另一种方法更容易。一路走来,我发现我的 Clojure 列表没有 .indexOf(Object object, int start) 方法。我是这样处理问题的:

      (defn index-of
      "Returns the index of item. If start is given indexes prior to
       start are skipped."
      ([coll item] (.indexOf coll item))
      ([coll item start]
        (let [unadjusted-index (.indexOf (drop start coll) item)]
          (if (= -1 unadjusted-index)
        unadjusted-index
        (+ unadjusted-index start)))))
      

      【讨论】:

        【解决方案8】:

        如果我们需要第一个索引,我们不需要循环整个集合。 some函数在第一次匹配后会短路。

        (defn index-of [x coll]
          (let [idx? (fn [i a] (when (= x a) i))]
          (first (keep-indexed idx? coll))))
        

        【讨论】:

          【解决方案9】:

          我会选择 reduce-kv

          (defn find-index [pred vec]
            (reduce-kv
              (fn [_ k v]
                (if (pred v)
                  (reduced k)))
              nil
              vec))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-08-15
            • 1970-01-01
            • 1970-01-01
            • 2023-01-10
            • 2023-04-03
            • 2011-10-05
            • 1970-01-01
            • 2023-03-16
            相关资源
            最近更新 更多