ベクトル内のアイテムのインデックスを見つけるにはどうすればよいですか?


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

ブライアンは明らかにこの質問への答えですが、以下では、cgrandとAlexStoddardが共謀して私が尋ねるべき質問に答えています。
John Lawrence Aspden 2011年

別の質問で正しい質問をすることを妨げるものは何もありません:)
Jonathan Benn 2015

回答:


135

ビルトイン:

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
甘い、ありがとうブライアン、私の医者検索者はおそらくそれがJavaであるためにindexOfを見つけられませんでした。私はそれに取り組む必要があります。
John Lawrence Aspden 2011年

2
@ジョン:はい。indexOfの前のドットは、Javaの相互運用を示します。java.lang.Stringのメソッド 'indexOf'を呼び出します。java.langはデフォルトでインポートされます。その他の例については、clojure.org / java_interop
dermatthias

25
それは、ベクターのだindexOf:それはない文字列の、呼び出されることの方法#<Method public int clojure.lang.APersistentVector.indexOf(java.lang.Object)>
vemv

44

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

非常に素晴らしい!これは私が期待していた種類の答えです。
John Lawrence Aspden 2011年

2
この回答のメリットに影響するわけではありませんが、seq-utilsはclojure.contrib.seqだけに変更されました。
John Lawrence Aspden 2011年

1
@ジョン、本当、私はそれを修正しました。ありがとう!
ポンサノ2011年

clojure.contib.seqclojure 1.6はどこで入手できますか?リストにライブラリがありません:dev.clojure.org/display/community/Where+Did+Clojure.Contrib+Go
d9k

@ d9k、「clojure.contrib名前空間がここにリストされているが、移行の詳細がない場合、それは誰もその名前空間を維持することを志願していないことを意味します。」の実装例を追加しましたpositions
ポンサノ2014年

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

ただし、インデックスをいじらないように警告したいと思います。ほとんどの場合、慣用的で扱いにくいClojureが生成されることはほとんどありません。


ああいい 'いつ'!インデックスについては一般的に同意しますが、csvファイルがあり、フィールドの名前がヘッダーにあり、各行からフィールド「フィールド」を取得したいので、「フィールド」を検索しています。ヘッダーで、次に行を何もしません。インターリーブに関係する奇妙なことを考えることができますが、読み取り可能な明示的なインデックスを使用しない良い方法はありますか?
John Lawrence Aspden 2011年

8
そのユースケース(csvヘッダー)がある場合、ルックアップを実行するためのマップを作成しました(一意の列ヘッダーを想定)。マップ、インデックスルックアップを実行するための私の機能です。(let [header-index(zipmap header-vector(iterate inc 0))] ...)
Alex Stoddard

1
ワオ。あなたは私が尋ねるべきだった質問に答えました!
John Lawrence Aspden 2011年

3
ええと、私はアレックスの解決策に非常に似た何かを提案したでしょう。(-> "colname" header-index row)そしてあなたはあなたの価値を持っています。
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)を単純な(range)に置き換えることもできます。
dribnet 2013年

6

私は自分の質問に答えようとしていましたが、ブライアンはもっと良い答えで私を打ち負かしました!

(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

これが私の貢献ですloop。ing構造を使用し、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))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.