Làm thế nào để tìm tất cả sự xuất hiện của một yếu tố trong danh sách?


378

index()sẽ chỉ đưa ra lần xuất hiện đầu tiên của một mục trong danh sách. Có một mẹo gọn gàng trả về tất cả các chỉ số trong một danh sách?


1
Tôi hơi bối rối trước câu hỏi này: bạn có muốn tìm kiếm một mục đệ quy trong tất cả các cấp của danh sách đa chiều hay bạn chỉ muốn tìm kiếm các lần xuất hiện ở cấp cao nhất của danh sách?
Anderson Green

22
Theo tôi nên có một phương pháp danh sách thực hiện chính xác điều này.
otocan

Câu trả lời:


545

Bạn có thể sử dụng một danh sách hiểu:

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

3
Trên các pythons cũ hơn, sử dụng bộ lọc () cho chức năng cơ bản giống nhau.
Gleno

44
Danh sách hiểu được hiển thị trong python ở 2.0, enumeratetại 2.3. Vì vậy, có, nếu Python của bạn là cổ xưa, sử dụng filter().
Steven Rumbalski

2
Kỹ thuật này sẽ không tìm thấy tất cả các lần xuất hiện của một mục trong một mảng nhiều chiều. Ví dụ, print([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])trả về []thay vì [[0, 1], [0, 0], [1, 1]].
Anderson Green

10
@AndersonGreen: Thuật ngữ "mảng đa chiều" cho thấy cấu trúc dữ liệu được đảm bảo có kích thước đồng nhất dọc theo mỗi trục của nó. Không có cấu trúc dữ liệu như vậy trong Python đơn giản. Có danh sách các danh sách, nhưng chúng rất khác với "mảng đa chiều". Nếu bạn muốn cái sau, bạn nên cân nhắc sử dụng NumPy, cho phép bạn làm những việc như (a == 1).nonzero()đối với mảng NumPy a.
Sven Marnach

2
@MadmanLee Nếu bạn muốn một cái gì đó nhanh chóng, hãy sử dụng NumPy. Xem câu trả lời của JoshAdel
Georgy

117

Mặc dù không phải là một giải pháp cho danh sách trực tiếp, nhưng numpythực sự tỏa sáng cho loại điều này:

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]

trả về:

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

Điều này có thể nhanh hơn đáng kể cho danh sách (mảng) với số lượng lớn các yếu tố so với một số giải pháp khác.


2
Tôi nhận thấy [0] ở cuối chuyển đổi một mảng thành một chuỗi. Tôi tò mò tại sao bạn chọn làm điều này.
amelia

5
@amelia [0]là cần thiết 'vì wheretrả lại một tuple(array([2, 8], dtype=int64),)
Winand

1
Này @Winand tôi đã đặt [0] nhưng vẫn nhận được cả hai phần. Đây là mã của tôi: (nrg.local_logs.all_id_resp_address là một danh sách) "ste =" 199,38.164.165 "value = np.where (nrg.local_logs.all_id_resp_address == ste) [0] cho tôi những gì tôi đã làm sai
Tomer

2
@Tomer trước hết all_id_resp_addressnên np.arraykhông list.
Winand

1
@Tomer bạn đã cố gắng để so sánh liststr, rõ ràng bạn thông qua Falseđể np.where. Khi bạn so sánh np.arrayvới smth. bạn nhận được một mảng các giá trị boolean. Sau đó np.wheretìm vị trí của tất cả các Truegiá trị của mảng đó.
Winand

29

Một giải pháp sử dụng 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)

Nó nhanh hơn nhiều so với việc hiểu danh sách với enumerate, cho các danh sách lớn. Nó cũng chậm hơn nhiều so với numpygiải pháp nếu bạn đã có mảng, nếu không thì chi phí chuyển đổi lớn hơn tốc độ tăng (được thử nghiệm trên danh sách số nguyên với 100, 1000 và 10000 phần tử).

LƯU Ý: Lưu ý thận trọng dựa trên nhận xét của Chris_Rands: giải pháp này nhanh hơn mức hiểu danh sách nếu kết quả đủ thưa thớt, nhưng nếu danh sách có nhiều phiên bản của phần tử đang được tìm kiếm (hơn ~ 15% danh sách , trong bài kiểm tra với danh sách 1000 số nguyên), việc hiểu danh sách nhanh hơn.


3
Bạn nói điều này nhanh hơn một danh sách comp, bạn có thể hiển thị thời gian biểu thị điều này không?
Chris_Rands

5
Đây là một thời gian dài trước đây, tôi có thể được sử dụng timeit.timeitvới các danh sách được tạo ngẫu nhiên. Tuy nhiên, đó là một điểm quan trọng và tôi cho rằng đó có thể là lý do tại sao bạn hỏi. Vào thời điểm đó, điều đó không xảy ra với tôi, nhưng tốc độ tăng chỉ đúng nếu kết quả đủ thưa thớt. Tôi vừa thử nghiệm với một danh sách đầy đủ các yếu tố để tìm kiếm, và nó chậm hơn nhiều so với việc hiểu danh sách.
Paulo Almeida

18

Làm thế nào về:

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 tìm các chỉ số cho tất cả các mục thỏa mãn một điều kiện.

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_itertoolslà một thư viện của bên thứ ba > pip install more_itertools.


1
có thể là tốt nếu lib này được thêm vào conda-forge (mặc dù conda installgần đây đã trở nên rất không ổn định trong hiệu suất)
matanster

4

Thêm một giải pháp (xin lỗi nếu trùng lặp) cho tất cả các lần xuất hiện:

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

Hoặc sử dụng range(python 3):

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

Dành cho (trăn 2):

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

Và sau đó (cả hai trường hợp):

print(l)

Là như mong đợi.


4

Sử dụng bộ lọc () trong python2.

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

Bạn có thể tạo một 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

Nhận tất cả các lần xuất hiện và vị trí của một hoặc nhiều mục (giống hệt nhau) trong danh sách

Với liệt kê (alist), bạn có thể lưu trữ phần tử đầu tiên (n) là chỉ mục của danh sách khi phần tử x bằng với những gì bạn tìm kiếm.

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

Hãy thực hiện chức năng của chúng tôi findindex

Hàm này lấy mục và danh sách làm đối số và trả về vị trí của mục trong danh sách, như chúng ta đã thấy trước đây.

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

Đầu ra


[1, 3, 5, 7]

Đơn giản

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

Đầu ra:

0
4

Câu trả lời này là dễ nhất đối với tôi để thực hiện trong mã hiện tại của tôi.
Ryan Harris

2

Sử dụng một for-loop:

  • Câu trả lời với enumeratehiểu danh sách là hiệu quả và pythonic hơn, tuy nhiên, câu trả lời này nhằm vào những sinh viên có thể không được phép sử dụng một số chức năng tích hợp sẵn đó .
  • tạo một danh sách trống indices
  • tạo vòng lặp với for i in range(len(x)):, về cơ bản lặp qua danh sách các vị trí chỉ mục[0, 1, 2, 3, ..., len(x)-1]
  • trong vòng lặp, thêm bất kỳ i, nơi x[i]phù hợp vớ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]
  • Các chức năng, get_indicesđược thực hiện với các gợi ý loại . Trong trường hợp này, danh sách, nlà một bó ints, do đó chúng tôi tìm kiếm value, cũng được định nghĩa là một int.

Sử dụng một while-loop.index:

  • Với .index, sử dụng try-exceptđể xử lý lỗiValueErrorsẽ xảy ra nếu valuekhông có trong danh sách.
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]

Tự xác định của bạn get_indeiceslà một chút nhanh hơn (~ 15%) so với hiểu danh sách bình thường. Tôi đang cố gắng để tìm ra nó.
Travis

1

Nếu bạn đang sử dụng Python 2, bạn có thể đạt được chức năng tương tự với điều này:

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

Nơi my_listđây là danh sách mà bạn muốn để có được các chỉ số của, vàvalue là giá trị được tìm kiếm. Sử dụng:

f(some_list, some_element)

1

Nếu bạn cần tìm kiếm tất cả các vị trí của phần tử giữa các chỉ số nhất định , bạn có thể nêu chúng:

[i for i,x in enumerate([1,2,3,2]) if x==2 & 2<= i <=3] # -> [3]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.