Как найти все вхождения элемента в списке?

379

index()просто даст первое вхождение элемента в списке. Есть ли хитрый трюк, который возвращает все индексы в списке?

Брюс
источник
1
Меня немного смущает этот вопрос: хотите ли вы искать элемент рекурсивно во всех уровнях многомерного списка или вы хотите искать только вхождения в верхнем уровне списка?
Андерсон Грин
22
По моему мнению, должен быть метод списка, который делает именно это.
otocan

Ответы:

546

Вы можете использовать понимание списка:

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]].
Андерсон Грин
10
@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])

Это может быть значительно быстрее для списков (массивов) с большим количеством элементов по сравнению с некоторыми другими решениями.

JoshAdel
источник
2
Я заметил, что [0] в конце преобразует массив в строку. Мне любопытно, почему вы решили это сделать.
Амелия
5
@amelia [0]необходим, потому что whereвозвращает кортеж(array([2, 8], dtype=int64),)
Winand
1
Привет @Win, и я вставил [0], но все еще получаю обе части. Вот мой код: (nrg.local_logs.all_id_resp_address - список) мне, что я сделал не так
Томер
2
@Tomer первую очередь all_id_resp_addressдолжно быть np.arrayне list.
Winand
1
@ Томер, который вы пытались сравнить, listи str, очевидно, вы перешли Falseк np.where. Когда вы сравниваете np.arrayс чем-л. вы получаете массив логических значений. Затем 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
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]
NPE
источник
10
occurrences = lambda s, lst: (i for i,e in enumerate(lst) if e == s)
list(occurrences(1, [1,2,3,1])) # = [0, 3]
phihag
источник
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.

pylang
источник
1
было бы неплохо, если бы этот lib был добавлен в 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)

Как и ожидалось.

U10-Forward
источник
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

Вы можете создать 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)
privatevoid
источник
2

Получение всех вхождений и положения одного или нескольких (идентичных) элементов в списке

С помощью enumerate (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
Giovanni G. PY
источник
Этот ответ мне было проще всего реализовать в моем существующем коде.
Райан Харрис
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)
Мистер Xcoder
источник
1

Если вам нужно найти все позиции элемента между определенными индексами , вы можете указать их:

[i for i,x in enumerate([1,2,3,2]) if x==2 & 2<= i <=3] # -> [3]
Денис Расулев
источник