Controleer of iets (niet) in een lijst in Python staat

Ik heb een lijst met tuples in Python en ik heb een voorwaardelijke waar ik de branch ALLEEN wil nemen als de tuple niet in de lijst staat (als het in de lijst staat, dan wil ik de if branch niet nemen)

if curr_x -1 > 0 and (curr_x-1 , curr_y) not in myList: 
    # Do Something

Dit werkt echter niet echt voor mij. Wat heb ik verkeerd gedaan?


Antwoord 1, autoriteit 100%

De bug zit waarschijnlijk ergens anders in je code, want het zou goed moeten werken:

>>> 3 not in [2, 3, 4]
False
>>> 3 not in [4, 5, 6]
True

Of met tupels:

>>> (2, 3) not in [(2, 3), (5, 6), (9, 1)]
False
>>> (2, 3) not in [(2, 7), (7, 3), "hi"]
True

Antwoord 2, autoriteit 4%

Hoe controleer ik of iets (niet) in een lijst in Python staat?

De goedkoopste en meest leesbare oplossing is het gebruik van de in operator (of in uw specifieke geval, not in). Zoals vermeld in de documentatie,

De operators in en not in testen op lidmaatschap. x in s evalueert tot
True als x lid is van s, en anders False. x not in s retourneert
de ontkenning van x in s.

Bovendien,

De operator not in is gedefinieerd om de inverse ware waarde van in te hebben.

y not in x is logischerwijs hetzelfde als not y in x.

Hier zijn een paar voorbeelden:

'a' in [1, 2, 3]
# False
'c' in ['a', 'b', 'c']
# True
'a' not in [1, 2, 3]
# True
'c' not in ['a', 'b', 'c']
# False

Dit werkt ook met tuples, aangezien tuples hashable zijn (als gevolg van het feit dat ze ook onveranderlijk zijn):

(1, 2) in [(3, 4), (1, 2)]
#  True

Als het object op de RHS een __contains__() methode, zal in het intern aanroepen, zoals vermeld in de laatste paragraaf van de Vergelijkingen van de documenten.

in en not in,
worden ondersteund door typen die itereerbaar zijn of de
__contains__() methode. U kunt bijvoorbeeld (maar mag niet) dit doen:

[3, 2, 1].__contains__(1)
# True

in kortsluitingen, dus als uw element aan het begin van de lijst staat, evalueert in sneller:

lst = list(range(10001))
%timeit 1 in lst
%timeit 10000 in lst  # Expected to take longer time.
68.9 ns ± 0.613 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
178 µs ± 5.01 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Als je meer wilt doen dan alleen controleren of een item in een lijst staat, zijn er opties:

  • list.index kan worden gebruikt om de index van een item op te halen. Als dat element niet bestaat, wordt een ValueError weergegeven.
  • list.count kan worden gebruikt als u het aantal exemplaren wilt tellen.

Het XY-probleem: heb je sets overwogen?

Stel uzelf deze vragen:

  • moet je controleren of een item meer dan één keer in een lijst staat?
  • Is deze controle gedaan binnen een lus, of een functie die herhaaldelijk wordt aangeroepen?
  • Zijn de items die u op uw lijst opslaat hashable? IOW, kun je hash op ze aanroepen?

Als je deze vragen met ‘ja’ hebt beantwoord, zou je in plaats daarvan een set moeten gebruiken. Een in lidmaatschapstest op lists is O(n) tijdscomplexiteit. Dit betekent dat python een lineaire scan van uw lijst moet maken, elk element moet bezoeken en het moet vergelijken met het zoekitem. Als u dit herhaaldelijk doet of als de lijsten groot zijn, brengt deze bewerking overhead met zich mee.

set objecten, aan de andere kant, hashen hun waarden voor constante lidmaatschapscontrole. De controle wordt ook gedaan met behulp van in:

1 in {1, 2, 3} 
# True
'a' not in {'a', 'b', 'c'}
# False
(1, 2) in {('a', 'c'), (1, 2)}
# True

Als je de pech hebt dat het element waarnaar je zoekt wel/niet aan het einde van je lijst staat, zal Python de lijst tot het einde hebben gescand. Dit blijkt uit de onderstaande tijden:

l = list(range(100001))
s = set(l)
%timeit 100000 in l
%timeit 100000 in s
2.58 ms ± 58.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
101 ns ± 9.53 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

Ter herinnering: dit is een geschikte optie zolang de elementen die je opslaat en opzoekt hashbaar zijn. IOW, het moeten ofwel onveranderlijke typen zijn, of objecten die __hash__ implementeren.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

4 × one =

Other episodes