Comment trouver toutes les occurrences d'un élément dans une liste?

378

index()donnera juste la première occurrence d'un élément dans une liste. Existe-t-il une astuce intéressante qui renvoie tous les indices d'une liste?

Bruce
la source
1
Je suis un peu confus par cette question: voulez-vous rechercher un élément récursivement à tous les niveaux d'une liste multidimensionnelle, ou voulez-vous uniquement rechercher des occurrences dans le niveau supérieur de la liste?
Anderson Green
22
À mon avis, il devrait y avoir une méthode de liste qui fait exactement cela.
Otocan

Réponses:

545

Vous pouvez utiliser une liste de compréhension:

indices = [i for i, x in enumerate(my_list) if x == "whatever"]
Sven Marnach
la source
3
Sur les anciens pythons, utilisez filter () pour essentiellement les mêmes fonctionnalités.
Gleno
44
Les compréhensions de liste sont apparues en python à 2.0, enumerateà 2.3. Alors oui, si votre Python est ancien, utilisez filter().
Steven Rumbalski
2
Cette technique ne trouvera pas toutes les occurrences d'un élément dans un tableau multidimensionnel. Par exemple, print([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])renvoie []au lieu de [[0, 1], [0, 0], [1, 1]].
Anderson Green
10
@AndersonGreen: Le terme "tableau multidimensionnel" suggère une structure de données qui est garantie d'avoir une taille uniforme le long de chacun de ses axes. Il n'y a pas une telle structure de données en Python simple. Il y a des listes de listes, mais elles sont très différentes des "tableaux multidimensionnels". Si vous voulez ce dernier, vous devriez envisager d'utiliser NumPy, qui vous permet de faire des choses comme (a == 1).nonzero()pour un tableau NumPy a.
Sven Marnach
2
@MadmanLee Si vous voulez quelque chose de rapide, utilisez NumPy. Voir la réponse de JoshAdel
Georgy
117

Bien que ce ne soit pas une solution pour les listes directement, numpybrille vraiment pour ce genre de chose:

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]

Retour:

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

Cela peut être beaucoup plus rapide pour les listes (tableaux) avec un grand nombre d'éléments par rapport à certaines des autres solutions.

JoshAdel
la source
2
J'ai remarqué que le [0] à la fin convertit ce qui serait un tableau en chaîne. Je suis curieux de savoir pourquoi vous avez choisi de faire cela.
amelia
5
@amelia [0]est nécessaire car whereretourne un tuple(array([2, 8], dtype=int64),)
Winand
1
Hé @Winand, j'ai mis [0] mais j'ai toujours les deux parties. Voici mon code: (nrg.local_logs.all_id_resp_address est une liste) "ste =" 199.38.164.165 "value = np.where (nrg.local_logs.all_id_resp_address == ste) [0]" Je serai heureux si vous pouvez dire moi ce que j'ai fait de mal
Tomer
2
@Tomer all_id_resp_addressne devrait tout d'abord np.arraypas l' être list.
Winand
1
@Tomer vous avez essayé de comparer listet str, évidemment, vous êtes passé Falseà np.where. Lorsque vous comparez np.arrayavec smth. vous obtenez un tableau de valeurs booléennes. Trouve ensuite les np.wherepositions de toutes les Truevaleurs de ce tableau.
Winand
29

Une solution utilisant 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)

C'est beaucoup plus rapide que la compréhension de liste avec enumerate, pour les grandes listes. Il est également beaucoup plus lent que la numpysolution si vous disposez déjà de la matrice, sinon le coût de conversion l'emporte sur le gain de vitesse (testé sur des listes entières avec 100, 1000 et 10000 éléments).

REMARQUE: une note de prudence basée sur le commentaire de Chris_Rands: cette solution est plus rapide que la compréhension de la liste si les résultats sont suffisamment clairsemés, mais si la liste contient de nombreuses instances de l'élément recherché (plus de ~ 15% de la liste , sur un test avec une liste de 1000 entiers), la compréhension de la liste est plus rapide.

Paulo Almeida
la source
3
Vous dites que c'est plus rapide qu'une liste de composition, pouvez-vous montrer vos horaires qui le démontrent?
Chris_Rands
5
C'était il y a longtemps, j'ai probablement utilisé timeit.timeitavec des listes générées aléatoirement. C'est un point important cependant, et je suppose que c'est peut-être pourquoi vous posez la question. À l'époque, cela ne m'est pas venu à l'esprit, mais les gains de vitesse ne sont vrais que si les résultats sont suffisamment clairsemés. Je viens de tester avec une liste pleine d'éléments à rechercher, et c'est beaucoup plus lent que la compréhension de la liste.
Paulo Almeida
18

Que diriez-vous:

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
la source
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
la source
8

more_itertools.locate recherche des indices pour tous les éléments qui remplissent une condition.

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_itertoolsest une bibliothèque tierce > pip install more_itertools.

pylang
la source
1
pourrait être bien si cette bibliothèque était ajoutée à conda-forge (bien qu'elle conda installsoit devenue très instable récemment)
matanster
4

Une autre solution (désolé si les doublons) pour toutes les occurrences:

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)
Artsiom Rudzenka
la source
4

Ou utilisez range(python 3):

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

Pour (python 2):

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

Et puis (dans les deux cas):

print(l)

Est comme prévu.

U10-Forward
la source
4

Utilisation de filter () en 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]
Niranjan Nagaraju
la source
2

Vous pouvez créer un dicton par défaut

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
la source
2

Obtention de toutes les occurrences et de la position d'un ou plusieurs éléments (identiques) dans une liste

Avec enumerate (alist), vous pouvez stocker le premier élément (n) qui est l'index de la liste lorsque l'élément x est égal à ce que vous recherchez.

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

Faisons notre fonction findindex

Cette fonction prend l'élément et la liste comme arguments et renvoie la position de l'élément dans la liste, comme nous l'avons vu précédemment.

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

Production


[1, 3, 5, 7]

Facile

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

Production:

0
4
Giovanni G. PY
la source
Cette réponse a été la plus simple à implémenter dans mon code existant.
Ryan Harris
2

Utilisation d'un for-loop:

  • Réponses avec enumerate et une compréhension de liste sont plus efficaces et pythoniques, cependant, cette réponse s'adresse aux étudiants qui peuvent ne pas être autorisés à utiliser certaines de ces fonctions intégrées .
  • créer une liste vide, indices
  • créer la boucle avec for i in range(len(x)):, qui itère essentiellement à travers une liste d'emplacements d'index[0, 1, 2, 3, ..., len(x)-1]
  • dans la boucle, ajoutez n'importe ioù, oùx[i] correspond à 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]
  • Les fonctions get_indices,, sont implémentées avec des indications de type . Dans ce cas, la liste n, est un tas deint s, donc nous recherchons value, également défini comme un int.

Utilisant un while-loop et .index:

  • Avec .index, utilisez try-exceptpour la gestion des erreurs car un ValueErrorse produira s'il valuene figure pas dans la liste.
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]
Trenton McKinney
la source
Votre auto-définition get_indeicesest un peu plus rapide (~ 15%) que la compréhension de liste normale. J'essaie de comprendre.
Travis
1

Si vous utilisez Python 2, vous pouvez obtenir les mêmes fonctionnalités avec ceci:

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

Où se my_listtrouve la liste dont vous souhaitez obtenir les index et valuela valeur recherchée. Usage:

f(some_list, some_element)
M. Xcoder
la source
1

Si vous devez rechercher toutes les positions des éléments entre certains indices , vous pouvez les indiquer:

[i for i,x in enumerate([1,2,3,2]) if x==2 & 2<= i <=3] # -> [3]
Denis Rasulev
la source