Як знайти усі входження елемента в списку?


377

index()просто дасть перше виникнення елемента в списку. Чи є акуратний трюк, який повертає всі показники у списку?


1
Мене трохи збентежило це питання: чи хочете ви шукати предмет рекурсивно на всіх рівнях багатовимірного списку, чи ви хочете шукати лише події на верхньому рівні списку?
Андерсон Грін

22
На мою думку, має бути метод списку, який робить саме це.
otocan

Відповіді:


544

Ви можете використати розуміння списку:

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

3
На старих пітонах використовуйте filter () для по суті того ж функціоналу.
Глено

44
Ознайомлення зі списком виявились у python у 2.0, enumerateу 2.3. Так що так, якщо ваш Python стародавній, використовуйте filter().
Стівен Румбальський

2
Ця методика не знайде всіх входження елементів у багатовимірному масиві. Наприклад, print([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])повертається []замість [[0, 1], [0, 0], [1, 1]].
Андерсон Грін

9
@AndersonGreen: Термін "багатовимірний масив" передбачає структуру даних, яка гарантовано має однаковий розмір уздовж кожної своєї осі. У простому Python немає такої структури даних. Існують списки списків, але вони сильно відрізняються від "багатовимірних масивів". Якщо ви хочете останнього, вам слід розглянути можливість використання NumPy, який дозволяє робити такі дії, як (a == 1).nonzero()для масиву NumPy a.
Свен Марнах

2
@MadmanLee Якщо ви хочете чогось швидкого, використовуйте NumPy. Дивіться відповідь ДжошАдела
Георгій

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] наприкінці перетворює те, що було б масивом у рядок. Мені цікаво, чому ви вирішили це зробити.
амелія

5
@amelia [0]потрібна, тому що whereповертається кортеж(array([2, 8], dtype=int64),)
Winand

1
Привіт @ Вінанд я вклав [0], але все-таки отримаю обидві частини. Ось мій код: (nrg.local_logs.all_id_resp_address - це список) "ste =" 199.38.164.165 "value = np.where (nrg.local_logs.all_id_resp_address == ste) [0]" Я буду радий, якщо ви можете сказати мені що я зробив не так
Томер

2
@Tomer першу чергу all_id_resp_addressповинно бути np.arrayНЕ list.
Вінанд

1
@Tomer ви намагалися порівнювати listі str, очевидно , ви пройшли Falseв np.where. Якщо порівнювати np.arrayз smth. ви отримуєте масив булевих значень. Потім np.whereзнаходить позиції всіх Trueзначень цього масиву.
Вінанд

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

4
Це було дуже давно, я, мабуть, використовував 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
могло б бути приємно, якби цей ліб був доданий до conda-forge (хоча conda installостаннім часом виявився дуже нестабільним у виконанні)
matanster

4

Ще одне рішення (вибачте, якщо дублікати) для всіх випадків:

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

Використання filter () у 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

Ви можете створити вирок за замовчуванням

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

Отримання всіх подій та положення одного чи кількох (однакових) елементів у списку

За допомогою перерахування (alist) ви можете зберігати перший елемент (n), що є індексом списку, коли елемент x дорівнює тому, що ви шукаєте.

>>> 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для обробки помилок, оскільки ValueErrorвиникне, якщо valueйого немає в списку.
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]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.