如何在向量中找到项目的索引?


83

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

(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)共同回答了我应该问的问题。
约翰劳伦斯·阿斯普登

没有什么可以阻止您在一个单独的问题中提出正确的问题:)
乔纳森·本

Answers:


134

内建:

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)

3
很好,谢谢Brian,我的文档搜索者未找到indexOf,大概是因为它是Java。我将不得不努力。
约翰·劳伦斯·阿斯普登

2
@约翰:是的。indexOf之前的点表示Java互操作。它在java.lang.String中调用方法“ indexOf”。默认情况下会导入java.lang。有关更多示例,请参见clojure.org/java_interop
dermatthias 2011年

25
indexOf是调用向量的方法,而不是调用String的方法:#<Method public int clojure.lang.APersistentVector.indexOf(java.lang.Object)>
vemv 2012年

44

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

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

非常好!这是我所期望的答案。
约翰·劳伦斯·阿斯普登

2
并不是说它会影响此答案的优点,但是seq-utils现在仅更改为clojure.contrib.seq。
约翰·劳伦斯·阿斯普登

1
@John,是的,我已修复。谢谢!
ponzao,2011年

在哪里获取clojure.contib.seqclojure 1.6?列表中没有图书馆:dev.clojure.org/display/community/Where+Did+Clojure.Contrib+Go
d9k 2014年

@ d9k,“如果此处列出了clojure.contrib名称空间,但没有迁移详细信息,则意味着没有人自愿维护该名称空间。” 我为添加了示例实现positions
ponzao 2014年

27
(defn find-thing [needle haystack]
  (keep-indexed #(when (= %2 needle) %1) haystack))

但是我要警告您不要摆弄索引:大多数情况下,它会减少惯用的,笨拙的Clojure。


噢,真好!我一般都同意索引,但是我有一个csv文件,并且字段的名称位于标题中,并且我想从每一行中获取字段“ field”,所以我正在做的是向上查找“ field”在标题中,然后在行中添加nth。我可以想到与交错有关的奇怪事情,但是有没有一种好方法,它不使用可读的显式索引?
约翰·劳伦斯·阿斯普登

8
当我有了用例-csv标头时-我刚刚构建了一个映射来进行查找(假设唯一的列标头)。然后,映射我执行索引查找的功能。(让[header-index(zipmap header-vector(iterate inc 0))] ...)
Alex Stoddard

1
哇。您回答了我应该问的问题!
约翰劳伦斯·阿斯普登

3
好吧,我会提出与Alex的解决方案非常相似的东西。(->“ colname”标头索引行),您便拥有了自己的价值。
cgrand 2011年

14

从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


2
感谢您发布此版本。从1.2开始,您还可以简单地将(范围)替换为(iterate inc 0)。
dribnet

6

我试图回答自己的问题,但是Brian为我打了一个更好的答案!

(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

3

这是我的贡献,使用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)))))

2

最近,我不得不多次查找索引,或者选择了索引,因为它比找出另一种解决问题的方法容易。一路上,我发现我的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)))))

0

我会用reduce-kv

(defn find-index [pred vec]
  (reduce-kv
    (fn [_ k v]
      (if (pred v)
        (reduced k)))
    nil
    vec))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.