Vraag De index van een item vinden met een lijst die het bevat in Python


Voor een lijst ["foo", "bar", "baz"] en een item in de lijst "bar", hoe krijg ik zijn index (1) in Python?


2238
2017-10-07 01:39


oorsprong


antwoorden:


>>> ["foo", "bar", "baz"].index("bar")
1

Referentie: Gegevensstructuren> Meer over lijsten

Aansluitingen volgen

Merk op dat dit misschien wel de schoonste manier is om de vraag te beantwoorden zoals gevraagd, index is een nogal zwakke component van de list API, en ik kan me de laatste keer dat ik het in woede heb gebruikt niet meer herinneren. In de opmerkingen is erop gewezen dat omdat dit antwoord zwaar wordt vermeld, het completer moet worden gemaakt. Sommige kanttekeningen over list.index volgen. Het is waarschijnlijk de moeite waard om hier eerst de docstring voor te bekijken:

>>> print(list.index.__doc__)
L.index(value, [start, [stop]]) -> integer -- return first index of value.
Raises ValueError if the value is not present.

Lineaire tijd-complexiteit in lijstlengte

Een index call controleert elk element van de lijst in volgorde totdat het een overeenkomst vindt. Als uw lijst lang is en u weet niet precies waar deze lijst voorkomt, kan deze zoekopdracht een knelpunt worden. In dat geval zou u een andere datastructuur moeten overwegen. Merk op dat als je ongeveer weet waar je de wedstrijd kunt vinden, je kunt geven index een hint. In dit fragment bijvoorbeeld l.index(999_999, 999_990, 1_000_000) is ongeveer vijf orden van grootte sneller dan recht l.index(999_999), omdat de eerste slechts 10 ingangen hoeft te doorzoeken, terwijl de laatste een miljoen zoekt:

>>> import timeit
>>> timeit.timeit('l.index(999_999)', setup='l = list(range(0, 1_000_000))', number=1000)
9.356267921015387
>>> timeit.timeit('l.index(999_999, 999_990, 1_000_000)', setup='l = list(range(0, 1_000_000))', number=1000)
0.0004404920036904514

Geeft alleen de index van de eerste wedstrijd aan zijn argument

Een oproep aan index doorzoekt de lijst in volgorde totdat het een overeenkomst vindt, en stopt daar. Als u indices van meer overeenkomsten verwacht, moet u een lijstbegrip of generatoruitdrukking gebruiken.

>>> [1, 1].index(1)
0
>>> [i for i, e in enumerate([1, 2, 1]) if e == 1]
[0, 2]
>>> g = (i for i, e in enumerate([1, 2, 1]) if e == 1)
>>> next(g)
0
>>> next(g)
2

De meeste plaatsen waar ik ooit zou hebben gebruikt index, Ik gebruik nu een lijstbegrip of generatorexpressie omdat ze meer generaliseerbaar zijn. Dus als je overweegt om te reiken index, kijk eens naar deze uitstekende python-functies.

Gooit als element niet in lijst voorkomt

Een oproep aan index resultaten in een ValueError als het item niet aanwezig is.

>>> [1, 1].index(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 2 is not in list

Als het item misschien niet in de lijst voorkomt, zou u dat ook moeten doen

  1. Controleer het eerst met item in my_list (schone, leesbare aanpak), of
  2. Wikkel het index bel naar a try/except blok dat vangt ValueError (waarschijnlijk sneller, tenminste als de lijst om te zoeken lang is en het item meestal aanwezig is.)

3299
2017-10-07 01:40



Een ding dat echt helpt bij het leren van Python is om de interactieve helpfunctie te gebruiken:

>>> help(["foo", "bar", "baz"])
Help on list object:

class list(object)
 ...

 |
 |  index(...)
 |      L.index(value, [start, [stop]]) -> integer -- return first index of value
 |

wat je vaak zal leiden naar de methode die je zoekt.


785
2017-10-07 13:19



De meeste antwoorden leggen uit hoe te vinden een enkele index, maar hun methoden retourneren niet meerdere indexen als het item meerdere keren in de lijst staat. Gebruik enumerate():

for i, j in enumerate(['foo', 'bar', 'baz']):
    if j == 'bar':
        print(i)

De index() functie geeft alleen de eerste occurrence als resultaat enumerate() retourneert alle exemplaren.

Als een begrip:

[i for i, j in enumerate(['foo', 'bar', 'baz']) if j == 'bar']

Hier is ook nog een kleine oplossing bij itertools.count() (dat is vrijwel dezelfde aanpak als opsommen):

from itertools import izip as zip, count # izip for maximum efficiency
[i for i, j in zip(count(), ['foo', 'bar', 'baz']) if j == 'bar']

Dit is efficiënter voor grotere lijsten dan gebruiken enumerate():

$ python -m timeit -s "from itertools import izip as zip, count" "[i for i, j in zip(count(), ['foo', 'bar', 'baz']*500) if j == 'bar']"
10000 loops, best of 3: 174 usec per loop
$ python -m timeit "[i for i, j in enumerate(['foo', 'bar', 'baz']*500) if j == 'bar']"
10000 loops, best of 3: 196 usec per loop

446
2018-06-19 22:31



Om alle indexen te krijgen:

 indexes = [i for i,x in enumerate(xs) if x == 'foo']

123
2018-06-25 15:07



index()geeft het eerste index van waarde!

| inhoudsopgave(...)
   | L.index (waarde, [start, [stop]]) -> integer - retourneer eerste index met waarde

def all_indices(value, qlist):
    indices = []
    idx = -1
    while True:
        try:
            idx = qlist.index(value, idx+1)
            indices.append(idx)
        except ValueError:
            break
    return indices

all_indices("foo", ["foo","bar","baz","foo"])

105
2017-08-30 09:40



Er zal een probleem optreden als het element niet in de lijst staat. Deze functie behandelt het probleem:

# if element is found it returns index of element else returns None

def find_element_in_list(element, list_element):
    try:
        index_element = list_element.index(element)
        return index_element
    except ValueError:
        return None

67
2018-04-16 10:19



a = ["foo","bar","baz",'bar','any','much']

indexes = [index for index in range(len(a)) if a[index] == 'bar']

57
2017-08-21 12:01



U moet een voorwaarde instellen om te controleren of het element dat u zoekt in de lijst staat

if 'your_element' in mylist:
    print mylist.index('your_element')
else:
    print None

39
2018-05-26 04:26



Alle voorgestelde functies reproduceren hier inherent taalgedrag maar verdoezelen wat er aan de hand is.

[i for i in range(len(mylist)) if mylist[i]==myterm]  # get the indices

[each for each in mylist if each==myterm]             # get the items

mylist.index(myterm) if myterm in mylist else None    # get the first index and fail quietly

Waarom een ​​functie met uitzonderingsafhandeling schrijven als de taal de methoden biedt om te doen wat u zelf wilt?


34
2018-05-16 16:45



Als u alle indexen wilt, dan kunt u gebruiken NumPy:

import numpy as np

array = [1, 2, 1, 3, 4, 5, 1]
item = 1
np_array = np.array(array)
item_index = np.where(np_array==item)
print item_index
# Out: (array([0, 2, 6], dtype=int64),)

Het is een duidelijke, leesbare oplossing.


27
2017-11-17 19:05



De index van een item vinden met een lijst die het bevat in Python

Voor een lijst ["foo", "bar", "baz"] en een item in de lijst "bar", wat is de schoonste manier om zijn index (1) in Python te krijgen?

Wel, er is zeker de indexmethode, die de index van de eerste keer voorkomt:

>>> l = ["foo", "bar", "baz"]
>>> l.index('bar')
1

Er zijn een aantal problemen met deze methode:

  • als de waarde niet in de lijst staat, krijgt u een ValueError
  • Als er meer dan een waarde in de lijst staat, krijg je alleen de index voor de eerste

Geen waarden

Als de waarde kan ontbreken, moet u de ValueError.

U kunt dit doen met een herbruikbare definitie als deze:

def index(a_list, value):
    try:
        return a_list.index(value)
    except ValueError:
        return None

En gebruik het als volgt:

>>> print(index(l, 'quux'))
None
>>> print(index(l, 'bar'))
1

En het nadeel hiervan is dat je waarschijnlijk een controle zult hebben op de geretourneerde waarde is of is not Geen:

result = index(a_list, value)
if result is not None:
    do_something(result)

Meerdere waarden in de lijst

Als u meer voorvallen zou hebben, zult u dat wel doen niet krijg volledige informatie met list.index:

>>> l.append('bar')
>>> l
['foo', 'bar', 'baz', 'bar']
>>> l.index('bar')              # nothing at index 3?
1

Je zou kunnen opsommen in een lijst om de indexen te begrijpen:

>>> [index for index, v in enumerate(l) if v == 'bar']
[1, 3]
>>> [index for index, v in enumerate(l) if v == 'boink']
[]

Als u geen occurrences heeft, kunt u dat controleren met Booleaanse controle van het resultaat, of gewoon niets doen als u de resultaten overloopt:

indexes = [index for index, v in enumerate(l) if v == 'boink']
for index in indexes:
    do_something(index)

Betere gegevens munging met panda's

Als je panda's hebt, kun je deze informatie gemakkelijk krijgen met een Series-object:

>>> import pandas as pd
>>> series = pd.Series(l)
>>> series
0    foo
1    bar
2    baz
3    bar
dtype: object

Een vergelijkingscontrole retourneert een reeks booleans:

>>> series == 'bar'
0    False
1     True
2    False
3     True
dtype: bool

Geef die reeks booleans door aan de reeks via subscript-notatie en je krijgt alleen de overeenkomende leden:

>>> series[series == 'bar']
1    bar
3    bar
dtype: object

Als u alleen de indexen wilt gebruiken, retourneert het indexkenmerk een reeks gehele getallen:

>>> series[series == 'bar'].index
Int64Index([1, 3], dtype='int64')

En als je ze in een lijst of tuple wilt hebben, geef je ze gewoon door aan de constructeur:

>>> list(series[series == 'bar'].index)
[1, 3]

Ja, je zou een lijstbegrip met opsomming ook kunnen gebruiken, maar dat is gewoon niet zo elegant, naar mijn mening - je doet testen voor gelijkheid in Python, in plaats van ingebouwde code in C te laten verwerken:

>>> [i for i, value in enumerate(l) if value == 'bar']
[1, 3]

Is dit een XY-probleem?

Het XY-probleem vraagt ​​naar uw poging tot oplossing in plaats van naar uw werkelijke probleem.

Waarom denk je dat je de index nodig hebt gezien een element in een lijst?

Als je de waarde al weet, waarom geef je dan om waar het in een lijst staat?

Als de waarde er niet is, het vangen van de ValueError is nogal breedsprakig - en dat wil ik liever vermijden.

Meestal ben ik toch bezig met het herhalen van de lijst, dus ik blijf meestal een aanwijzing houden voor interessante informatie om de index met opsommen.

Als je gegevens mijdt, zou je waarschijnlijk panda's moeten gebruiken - die veel elegantere tools bevat dan de pure Python-oplossingen die ik heb laten zien.

Ik kan me niet herinneren dat ik nodig heb list.index, mezelf. Ik heb echter de standaardbibliotheek van Python bekeken, en ik zie er enkele uitstekende toepassingen voor.

Er zijn veel, veel toepassingen voor in idlelib, voor GUI en tekst-parsing.

De keyword module gebruikt het om commentaarmarkeringen in de module te vinden om automatisch de lijst met trefwoorden erin te regenereren via metaprogrammering.

In Lib / mailbox.py lijkt het het te gebruiken als een geordende toewijzing:

key_list[key_list.index(old)] = new

en

del key_list[key_list.index(key)]

In Lib / http / cookiejar.py lijkt de volgende maand te worden gebruikt:

mon = MONTHS_LOWER.index(mon.lower())+1

In Lib / tarfile.py vergelijkbaar met distutils om een ​​segment op een item te krijgen:

members = members[:members.index(tarinfo)]

In Lib / pickletools.py:

numtopop = before.index(markobject)

Wat deze gebruiksmogelijkheden gemeen lijken te zijn, is dat ze lijken te werken op lijsten van beperkte grootte (belangrijk vanwege O (n) opzoektijd voor list.index) en ze worden meestal gebruikt bij het parseren (en UI in het geval van Niet actief).

Hoewel er use-cases voor zijn, zijn ze tamelijk zeldzaam. Als u merkt dat u op zoek bent naar dit antwoord, vraag uzelf dan af wat u het meest directe gebruik van de hulpprogramma's in deze taal voor uw use-case kunt doen.


22
2017-08-22 03:08