0%

Dictionaries en andere verzamelingen · oefening

Doorzoek een lijst met records

Een catalogus is nuttig wanneer een programma één record via een veld kan vinden.

catalog = [
    {"title": "Kindred", "year": 1979},
    {"title": "Dune", "year": 1965},
]

Je kunt de lijst niet om "Dune" als sleutel vragen. De lijst bevat dictionaries, dus doorzoek de records één voor één:

for item in catalog:
    if item["title"] == "Dune":
        print(item)

Zet het zoeken in een functie

Een zoekfunctie kan de overeenkomende dictionary teruggeven:

def find_by_title(catalog, query):
    for item in catalog:
        if item["title"] == query:
            return item

    return None

Als een titel overeenkomt, beëindigt de eerste return de functie direct en stuurt die dictionary naar de aanroeper.

Als de lus eindigt zonder overeenkomst, bereikt de uitvoering return None. None maakt “geen overeenkomend record” expliciet.

Hoofdstuk 8 liet al zien dat return de huidige functieaanroep beëindigt en dat een functie zonder bruikbaar resultaat None oplevert. Hier wordt dat gedrag onderdeel van de afspraak voor een zoekopdracht:

  • een overeenkomst geeft een dictionary terug;

  • geen overeenkomst geeft None terug.

De twee paden hieronder laten zien waarom de laatste return None na de lus hoort: een overeenkomst leidt tot een vroege terugkeer, terwijl voor een ontbrekende zoekterm eerst elk record bekeken moet worden. “Matching query” is een zoekterm met een overeenkomst, “Missing query” een zoekterm zonder overeenkomst. “No” betekent geen overeenkomst en “Match” betekent wel een overeenkomst. “Return record” geeft het record terug; “Return None” geeft de speciale waarde terug die aangeeft dat er niets is gevonden.

Twee zoekpaden vergelijken records in volgorde; Dune geeft direct het overeenkomende record terug, terwijl Solaris het einde bereikt en None teruggeeft.

Schoon beide kanten op

Mensen kunnen andere hoofdletters of spaties aan de buitenkant typen. Schoon de zoekterm één keer op:

clean_query = query.strip().lower()

Voeg die opschoning toe aan de volledige functie en vergelijk met een versie van elke opgeslagen titel in kleine letters:

def find_by_title(catalog, query):
    clean_query = query.strip().lower()

    for item in catalog:
        if item["title"].lower() == clean_query:
            return item

    return None

De oorspronkelijke titel in de dictionary blijft ongewijzigd.

Controleer het resultaat

Gebruik is not None wanneer er een overeenkomst is gevonden:

match = find_by_title(catalog, "  DUNE ")

if match is not None:
    print(match["year"])
else:
    print("No matching title.")

is None en is not None zijn de standaardcontroles voor deze ene speciale waarde.

Wat bevat match?

def find_by_name(records, query):
    for record in records:
        if record["name"].lower() == query.strip().lower():
            return record
    return None

places = [
    {"name": "Kyoto", "country": "Japan"},
    {"name": "Lima", "country": "Peru"},
]

match = find_by_name(places, " lima ")

Opdracht

Maak find_by_title(catalog, query) af.

De functie moet:

  1. query opschonen met .strip().lower();

  2. de dictionaryrecords in catalog doorlopen;

  3. de opgeschoonde zoekterm vergelijken met elke titel in kleine letters;

  4. de overeenkomende dictionary direct teruggeven;

  5. na de lus None teruggeven als niets overeenkwam.

Behoud de bestaande aanroep en resultaatcontrole.

Verwachte uitvoer:

Found: Dune (1965)

De beoordelaar roept je functie ook aan met een andere titel en met een ontbrekende titel.