Sök…


Anmärkningar

Alla sökande algoritmer på iterables som innehåller n element har O(n) komplexitet. Endast specialiserade algoritmer som bisect.bisect_left() kan vara snabbare med O(log(n)) komplexitet.

Få index för strängar: str.index (), str.rindex () och str.find (), str.rfind ()

String har också en index men också mer avancerade alternativ och den extra str.find . För båda dessa finns det en kompletterande omvänd metod.

astring = 'Hello on StackOverflow'
astring.index('o')  # 4
astring.rindex('o') # 20

astring.find('o')   # 4
astring.rfind('o')  # 20

Skillnaden mellan index / rindex och find / rfind är vad som händer om substrängen inte hittas i strängen:

astring.index('q') # ValueError: substring not found
astring.find('q')  # -1

Alla dessa metoder tillåter ett start- och slutindex:

astring.index('o', 5)    # 6
astring.index('o', 6)    # 6 - start is inclusive
astring.index('o', 5, 7) # 6
astring.index('o', 5, 6) #  - end is not inclusive

ValueError: substring hittades inte

astring.rindex('o', 20) # 20 
astring.rindex('o', 19) # 20 - still from left to right

astring.rindex('o', 4, 7) # 6

Söker efter ett element

Alla inbyggda samlingar i Python implementerar ett sätt att kontrollera elementmedlemskap med in .

Lista

alist = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
5 in alist   # True
10 in alist  # False

tupel

atuple = ('0', '1', '2', '3', '4')
4 in atuple    # False
'4' in atuple  # True

Sträng

astring = 'i am a string'
'a' in astring   # True
'am' in astring  # True
'I' in astring   # False

Uppsättning

aset = {(10, 10), (20, 20), (30, 30)}
(10, 10) in aset  # True
10 in aset        # False

dict

dict är lite speciell: det normala in endast kontroller nycklarna. Om du vill söka i värden måste du ange det. Samma om du vill söka efter nyckelvärdespar .

adict = {0: 'a', 1: 'b', 2: 'c', 3: 'd'}
1 in adict                 # True   - implicitly searches in keys
'a' in adict               # False
2 in adict.keys()          # True   - explicitly searches in keys
'a' in adict.values()      # True   - explicitly searches in values
(0, 'a') in adict.items()  # True   - explicitly searches key/value pairs

Hämta indexlistan och tuples: list.index (), tuple.index ()

list och tuple har ett index -metoden för att få positionen för elementet:

alist = [10, 16, 26, 5, 2, 19, 105, 26]
# search for 16 in the list
alist.index(16) # 1
alist[1]        # 16

alist.index(15)

ValueError: 15 finns inte i listan

Men returnerar bara positionen för det först hittade elementet:

atuple = (10, 16, 26, 5, 2, 19, 105, 26)
atuple.index(26)   # 2
atuple[2]          # 26
atuple[7]          # 26 - is also 26!

Söker nyckel (er) efter ett värde i dict

dict har ingen inbyggd metod för att söka efter ett värde eller nyckel eftersom ordböcker är oordnade. Du kan skapa en funktion som får nyckeln (eller nycklarna) för ett angivet värde:

def getKeysForValue(dictionary, value):
    foundkeys = []
    for keys in dictionary:
        if dictionary[key] == value:
            foundkeys.append(key)
    return foundkeys

Detta kan också skrivas som en motsvarande listaförståelse:

def getKeysForValueComp(dictionary, value): 
    return [key for key in dictionary if dictionary[key] == value]

Om du bara bryr dig om en nyckel som hittades:

def getOneKeyForValue(dictionary, value):
    return next(key for key in dictionary if dictionary[key] == value)

De två första funktionerna returnerar en list med alla keys som har det angivna värdet:

adict = {'a': 10, 'b': 20, 'c': 10}
getKeysForValue(adict, 10)     # ['c', 'a'] - order is random could as well be ['a', 'c']
getKeysForValueComp(adict, 10) # ['c', 'a'] - dito
getKeysForValueComp(adict, 20) # ['b']
getKeysForValueComp(adict, 25) # []

Den andra returnerar bara en nyckel:

getOneKeyForValue(adict, 10)   # 'c'  - depending on the circumstances this could also be 'a'
getOneKeyForValue(adict, 20)   # 'b'

och höja en StopIteration - Exception om värdet inte finns i dict :

getOneKeyForValue(adict, 25)

StopIteration

Hämta indexet för sorterade sekvenser: bisect.bisect_left ()

Sorterade sekvenser tillåter användning av snabbare bisect.bisect_left() : bisect.bisect_left() 1 :

import bisect

def index_sorted(sorted_seq, value):
    """Locate the leftmost value exactly equal to x or raise a ValueError"""
    i = bisect.bisect_left(sorted_seq, value)
    if i != len(sorted_seq) and sorted_seq[i] == value:
        return i
    raise ValueError

alist = [i for i in range(1, 100000, 3)] # Sorted list from 1 to 100000 with step 3
index_sorted(alist, 97285) # 32428
index_sorted(alist, 4)     # 1
index_sorted(alist, 97286)

ValueError

För mycket stora sorterade sekvenser kan hastighetsförstärkningen vara ganska hög. För den första sökningen ungefär 500 gånger så snabbt:

%timeit index_sorted(alist, 97285)
# 100000 loops, best of 3: 3 µs per loop
%timeit alist.index(97285)
# 1000 loops, best of 3: 1.58 ms per loop

Även om det är lite långsammare om elementet är ett av de allra första:

%timeit index_sorted(alist, 4)
# 100000 loops, best of 3: 2.98 µs per loop
%timeit alist.index(4)
# 1000000 loops, best of 3: 580 ns per loop

Söker kapslade sekvenser

Att söka i kapslade sekvenser som en list med tuple kräver ett tillvägagångssätt som att söka på tangenterna efter värden i dict men behöver anpassade funktioner.

Indexet för den yttersta sekvensen om värdet hittades i sekvensen:

def outer_index(nested_sequence, value):
    return next(index for index, inner in enumerate(nested_sequence) 
                      for item in inner 
                      if item == value)

alist_of_tuples = [(4, 5, 6), (3, 1, 'a'), (7, 0, 4.3)]
outer_index(alist_of_tuples, 'a')  # 1
outer_index(alist_of_tuples, 4.3)  # 2

eller indexet för den yttre och den inre sekvensen:

def outer_inner_index(nested_sequence, value):
    return next((oindex, iindex) for oindex, inner in enumerate(nested_sequence) 
                                 for iindex, item in enumerate(inner) 
                                 if item == value)

outer_inner_index(alist_of_tuples, 'a') # (1, 2)
alist_of_tuples[1][2]  # 'a'

outer_inner_index(alist_of_tuples, 7)   # (2, 0)
alist_of_tuples[2][0]  # 7

I allmänhet ( inte alltid ) att använda next och ett generatoruttryck med villkor för att hitta den första förekomsten av det sökta värdet är det mest effektiva tillvägagångssättet.

Söker i anpassade klasser: __contain__ och __iter__

För att tillåta användning av in för anpassade klasser måste klassen antingen tillhandahålla den magiska metoden __contains__ eller, om inte, en __iter__ __-metod.

Anta att du har en klass som innehåller en list med list :

class ListList:
    def __init__(self, value):
        self.value = value
        # Create a set of all values for fast access
        self.setofvalues = set(item for sublist in self.value for item in sublist)
        
    def __iter__(self):
        print('Using __iter__.')
        # A generator over all sublist elements
        return (item for sublist in self.value for item in sublist)
        
    def __contains__(self, value):
        print('Using __contains__.')
        # Just lookup if the value is in the set
        return value in self.setofvalues

        # Even without the set you could use the iter method for the contains-check:
        # return any(item == value for item in iter(self))

Att använda medlemstestning är möjligt genom att använda in :

a = ListList([[1,1,1],[0,1,1],[1,5,1]])
10 in a    # False
# Prints: Using __contains__.
5 in a     # True
# Prints: Using __contains__.

även efter att du har __contains__ metoden __contains__ :

del ListList.__contains__
5 in a     # True
# Prints: Using __iter__.

Obs: Den looping in (som i for i in a ) använder alltid __iter__ även om klass implementerar en __contains__ metod.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow