Datensatz in Python nach den Werten der in ihm enthaltenen Dictionaries filtern

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mcl33
User
Beiträge: 7
Registriert: Donnerstag 19. November 2015, 13:47

Hallo zusammen:

folgendes Problem: ich habe einen Datensatz (aus OpenStreetMap), der folgendermaßen strukturiert ist:

Code: Alles auswählen

ways = [(way_id1, {'key': 'value'}, [coord_id11, coord_id12, coord_id13]),
        (way_id2, {'key': 'value'}, [coord_id21, coord_id22, coord_id23]),
        (way_id3, {'key': 'value'}, [coord_id31, coord_id32, coord_id33]]
D.h. eine Liste aus Tuples, welche wiederum jeweils aus einer Variable, einem Dictionary und einer Liste bestehen.

Ich möchte der Liste "ways" nur jene Tuples behalten, welch im Dictionary bestimmte Werte haben, und zwar 'highway': 'secondary und 'highway': 'tertiary'. Alle anderen Tuples, die entweder ein leeres Dictionary haben oder andere Values zum Key, sollen dementsprechend gelöscht werden.
Auch kann das Dictionary im Tuple auf die verbleibende Value reduziert werden.

Als Python-Neuling habe ich das Ganze folgendermaßen gelöst, bei sehr großen Datensätzen, scheint dies aber sehr ineffizient zu sein:

Code: Alles auswählen

relevant_ways = []
for (way_id, way_tag, way_refs) in ways:
	if 'highway' in way_tag.keys() and way_tag['highway'] in ['secondary', 'tertiary']:
		relevant_ways.append((way_id, way_tag['highway'], way_refs))
Hat jemand einen besseren, insbesondere effizienteren weg?

Danke für eure Hilfe!
Michael
__________________
Hier noch ein kurzer realer Auszug aus einem originalen Datensatz zum Probieren:

Code: Alles auswählen

ways = [(34428729, {'highway': 'living_street'}, [395670212, 1418765744, 395670248, 395670251]),
        (128360258, {}, [1418764756, 1418765545, 1418765699, 1418764526, 1418764756]),
        (132606717, {'highway': 'secondary'}, [96916521, 96916524, 96916531, 96916535, 96916537, 96916539, 96916542, 2890145250, 96916548, 308345678, 96916552, 96916555, 2489391717, 96916558, 96916561, 3770243842, 96916563]),
        (132606700, {'highway': 'primary'}, [413283866, 413283867, 413283868, 33466827]), (133792713, {}, [1352845081, 1472526502, 1472526503, 1472526506, 1472526504, 1472526501, 1472526500, 1472526499, 1472526498, 1472526497, 1472526496, 1472526494]),
        (97534711, {}, [1129255618, 1129256133, 1129255674, 1129255705, 1129255997, 1129255874, 1129256160, 1129256048, 1129255582, 1129255317, 1129255748, 1129255771, 1129255599, 1129256074, 1129255618]),
        (32571664, {'highway': 'tertiary'}, [355693493, 297777213, 381225556, 2308946489, 297777222, 349236565, 349236561, 297777231, 349236514]),
        (28000595, {'highway': 'tertiary'}, [307460606, 1113060707, 766466339, 1113060320, 1113061560, 307460607, 307464071, 307462882])]
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Die Abfrage lässt sich stark vereinfachen:

Code: Alles auswählen

if way_tag.get('highway') in ('secondary', 'tertiary'):
    # u.s.w.
Die `get()`-Methode liefert entweder den Wert für den angegebenen Schlüssel oder `None`, falls der Schlüssel nicht existiert.

Die Sequenz mit den gesuchten Begriffen würde ich übrigens vor der Schleife an einen Namen binden. Dann wird sie nicht für jeden Schleifendurchlauf neu erstellt.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wenn man schon etwas geübter in Python ist, dann könnte man auch das `yield`-Statement einsetzen:

Code: Alles auswählen

def get_relevant_ways(ways, relevant_types):
    for way_id, way_tag, way_refs in ways:
        way_type= way_tag.get('highway')
        if way_type in relevant_types:
            yield way_id, way_type, way_refs

def print_relevant_ways(ways)
    # Anwendungsbeispiel
    relevant_types = ['secondary', 'tertiary']
    for way in get_relevant_ways(ways, relevant_types):
        print(way)
Durch `yield` wird das Anlegen einer Liste für das Zwischenspeichern der Ergebnisse vermieden. Stattdessen führt jeder Iterationsschritt in der `for`-Schleife des Aufrufers `print_relevant_ways()` dazu, dass erst dann der "zugehörige" Iterationsschritt in `get_relevant_ways()` begangen wird. Oder genau genommen wird dann solange "nach vorne gesprungen" bis die Ausführung wieder auf das `yield`-Statement trifft (d.h. wenn die `if`-Bedingung zutrifft). Es ist also so als ob man eine erdachte `get_next_relevant_way()`-Funktion hätte, die immer wieder aufgerufen wird.

Das Vermeiden der Liste kann bei großen Datenmengen äußerst hilfreich sein.
Antworten