リスト内の要素のすべての出現を見つける方法は?


378

index()リスト内の項目の最初の出現を与えるだけです。リスト内のすべてのインデックスを返すきちんとしたトリックはありますか?


1
私はこの質問に少し混乱しています。多次元リストのすべてのレベルでアイテムを再帰的に検索しますか、それともリストの最上位レベルのオカレンスのみを検索しますか?
アンダーソングリーン

22
私の意見では、まさにこれを行うリストメソッドがあるはずです。
otocan

回答:


545

リスト内包表記を使用できます。

indices = [i for i, x in enumerate(my_list) if x == "whatever"]

3
古いpythonでは、基本的に同じ機能のためにfilter()を使用します。
グレノ2011年

44
リスト内包表記はPythonの2.0、2.3で表示されましたenumerate。ですから、Pythonが古い場合はを使用してくださいfilter()
Steven Rumbalski、2011年

2
この手法では、多次元配列内のアイテムのすべての出現を見つけることはできません。たとえば、ではなくをprint([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])返します。[][[0, 1], [0, 0], [1, 1]]
アンダーソングリーン

10
@AndersonGreen:「多次元配列」という用語は、その各軸に沿って均一なサイズを持つことが保証されているデータ構造を示唆しています。プレーンなPythonにはそのようなデータ構造はありません。リストのリストはありますが、「多次元配列」とは大きく異なります。後者が必要な場合は、NumPyの使用を検討する必要があります。これにより(a == 1).nonzero()、NumPy配列の場合と同様のことが可能になりますa
スヴェンマルナッハ2014

2
@MadmanLee高速なものが必要な場合は、NumPyを使用してください。JoshAdel
Georgy

117

リストの直接的な解決策ではありませnumpyんが、この種のことには本当に優れています。

import numpy as np
values = np.array([1,2,3,1,2,4,5,6,3,2,1])
searchval = 3
ii = np.where(values == searchval)[0]

戻り値:

ii ==>array([2, 8])

これは、他のソリューションのいくつかと比較して、要素の数が多いリスト(配列)の場合に大幅に高速化できます。


2
最後の[0]が配列になるものを文字列に変換することに気づきました。なぜこれを選んだのか、私は知りたいです。
amelia 2016年

5
@amelia [0]が必要なのwhereは、タプルが返されるからです(array([2, 8], dtype=int64),)
Winand

1
ちょっと@Winand [0]に入れましたが、それでも両方のパーツを取得します。これが私のコードです:(nrg.local_logs.all_id_resp_address is a list) "ste =" 199.38.164.165 "value = np.where(nrg.local_logs.all_id_resp_address == ste)[0]"教えていただければ幸いです私が間違っていたものを私
Tomer

2
@Tomerはまず第一であってall_id_resp_addressはなりnp.arrayませんlist
Winand

1
あなたが比較してみました@Tomer liststr、明らかにあなたは渡さFalsenp.wherenp.arraysmth と比較すると。ブール値の配列を取得します。次に、その配列のnp.whereすべてのTrue値の位置を見つけます。
Winand

29

を使用したソリューションlist.index

def indices(lst, element):
    result = []
    offset = -1
    while True:
        try:
            offset = lst.index(element, offset+1)
        except ValueError:
            return result
        result.append(offset)

enumerate大きなリストの場合、でのリストの理解よりもはるかに高速です。また、すでにアレイがある場合は、numpyソリューションよりもはるかに遅くなります。それ以外の場合は、変換のコストがスピードゲインを上回ります(100、1000、10000要素の整数リストでテスト)。

注: Chris_Randsのコメントに基づく注意事項結果が十分にスパースである場合、このソリューションはリスト内包よりも高速ですが、リストに検索対象の要素のインスタンスが多数ある場合(リストの約15%以上) 、1000個の整数のリストを使用したテストでは、リストの理解が速くなります。


3
これはリストコンプよりも速いとおっしゃっていますが、これを実証するタイミングを示すことができますか?
Chris_Rands 2017年

5
これはずっと前のことですが、おそらくtimeit.timeitランダムに生成されたリストを使用していました。それは重要な点ですが、それがあなたの質問の理由かもしれません。当時私には起こりませんでしたが、速度の向上は、結果が十分にまばらである場合にのみ当てはまります。検索対象の要素をすべて含むリストでテストしたところ、リストの理解よりもはるかに遅い。
パウロアルメイダ

18

どうですか:

In [1]: l=[1,2,3,4,3,2,5,6,7]

In [2]: [i for i,val in enumerate(l) if val==3]
Out[2]: [2, 4]

10
occurrences = lambda s, lst: (i for i,e in enumerate(lst) if e == s)
list(occurrences(1, [1,2,3,1])) # = [0, 3]

8

more_itertools.locate 条件を満たすすべてのアイテムのインデックスを検索します。

from more_itertools import locate


list(locate([0, 1, 1, 0, 1, 0, 0]))
# [1, 2, 4]

list(locate(['a', 'b', 'c', 'b'], lambda x: x == 'b'))
# [1, 3]

more_itertoolsはサードパーティのライブラリ> pip install more_itertoolsです。


1
このlibがconda-forgeに追加された場合は良いかもしれません(conda install最近のパフォーマンスは非常に不安定になっています)
matanster

4

すべての発生に対するもう1つの解決策(重複している場合は申し訳ありません):

values = [1,2,3,1,2,4,5,6,3,2,1]
map(lambda val: (val, [i for i in xrange(len(values)) if values[i] == val]), values)

4

または使用range(python 3):

l=[i for i in range(len(lst)) if lst[i]=='something...']

(python 2)の場合:

l=[i for i in xrange(len(lst)) if lst[i]=='something...']

そして(両方の場合):

print(l)

さすがです。


4

python2でfilter()を使用します。

>>> q = ['Yeehaw', 'Yeehaw', 'Googol', 'B9', 'Googol', 'NSM', 'B9', 'NSM', 'Dont Ask', 'Googol']
>>> filter(lambda i: q[i]=="Googol", range(len(q)))
[2, 4, 9]

2

defaultdictを作成できます

from collections import defaultdict
d1 = defaultdict(int)      # defaults to 0 values for keys
unq = set(lst1)              # lst1 = [1, 2, 2, 3, 4, 1, 2, 7]
for each in unq:
      d1[each] = lst1.count(each)
else:
      print(d1)

2

リスト内の1つ以上の(同一の)アイテムのすべての出現と位置を取得する

enumerate(alist)を使用すると、要素xが探しているものと等しい場合に、リストのインデックスである最初の要素(n)を格納できます。

>>> alist = ['foo', 'spam', 'egg', 'foo']
>>> foo_indexes = [n for n,x in enumerate(alist) if x=='foo']
>>> foo_indexes
[0, 3]
>>>

関数findindexを作成しましょう

この関数は引数としてアイテムとリストを取り、前に見たようにリスト内のアイテムの位置を返します。

def indexlist(item2find, list_or_string):
  "Returns all indexes of an item in a list or a string"
  return [n for n,item in enumerate(list_or_string) if item==item2find]

print(indexlist("1", "010101010"))

出力


[1, 3, 5, 7]

シンプルな

for n, i in enumerate([1, 2, 3, 4, 1]):
    if i == 1:
        print(n)

出力:

0
4

この答えは、既存のコードに実装するのが最も簡単でした。
ライアンハリス

2

を使用するfor-loop

  • 回答enumerateし、リストの内包が、より効率的かつ神託ある、しかし、この答えは、それらのいくつかの使用を許可されない場合があり、学生を対象として組み込み関数を
  • 空のリストを作成し、 indices
  • を使用してループを作成しますfor i in range(len(x)):。これは、基本的にインデックスの場所のリストを反復処理します[0, 1, 2, 3, ..., len(x)-1]
  • ループ内、いずれかを追加iところ、x[i]マッチがあるとvalueし、indices
def get_indices(x: list, value: int) -> list:
    indices = list()
    for i in range(len(x)):
        if x[i] == value:
            indices.append(i)
    return indices

n = [1, 2, 3, -50, -60, 0, 6, 9, -60, -60]
print(get_indices(n, -60))

>>> [4, 8, 9]
  • 関数は型ヒントでget_indices実装されています。この場合、リストnは一連のintsであるためvalue、としても定義されているを検索しintます。

使用するwhile-loop.index

  • では.index、がリストにない場合に発生するため、エラー処理に使用try-exceptますValueErrorvalue
def get_indices(x: list, value: int) -> list:
    indices = list()
    i = 0
    while True:
        try:
            # find an occurrence of value and update i to that index
            i = x.index(value, i)
            # add i to the list
            indices.append(i)
            # advance i by 1
            i += 1
        except ValueError as e:
            break
    return indices

print(get_indices(n, -60))
>>> [4, 8, 9]

自己定義get_indeicesは、通常のリスト内包よりも少し高速(〜15%)です。私はそれを理解しようとしています。
トラビス

1

Python 2を使用している場合、これで同じ機能を実現できます。

f = lambda my_list, value:filter(lambda x: my_list[x] == value, range(len(my_list)))

my_listインデックスを取得するリストはどこにあり、value検索される値はどこですか。使用法:

f(some_list, some_element)

1

特定のインデックス間のすべての要素の位置を検索する必要がある場合は、それらを指定できます。

[i for i,x in enumerate([1,2,3,2]) if x==2 & 2<= i <=3] # -> [3]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.