Ich habe mich gefragt: Wäre es möglich, mit unvollständigen Schlüsseln auf diktierte Werte zuzugreifen (solange es nicht mehr als einen Eintrag für eine bestimmte Zeichenfolge gibt)? Beispielsweise:

my_dict = {'name': 'Klauss', 'age': 26, 'Date of birth': '15th july'}
print my_dict['Date']
>> '15th july'

Ist das möglich? Wie könnte es gemacht werden?

23
Roman Rdgz 14 Juni 2013 im 14:52

7 Antworten

Beste Antwort

Sie können dies nicht direkt mit dict[keyword] tun. Sie müssen das Diktat durchlaufen und jeden Schlüssel mit dem Schlüsselwort abgleichen und den entsprechenden Wert zurückgeben, wenn das Schlüsselwort gefunden wird. Dies wird eine O(N) Operation sein.

>>> my_dict = {'name': 'Klauss', 'age': 26, 'Date of birth': '15th july'}
>>> next(v for k,v in my_dict.items() if 'Date' in k)
'15th july'

Um alle diese Werte zu erhalten, verwenden Sie ein Listenverständnis:

>>> [ v for k,v in my_dict.items() if 'Date' in k]
['15th july']

Verwenden Sie str.startswith, wenn Sie nur die Werte möchten, deren Schlüssel mit 'Datum' beginnen:

>>> next( v for k,v in my_dict.items() if k.startswith('Date'))
'15th july'
>>> [ v for k,v in my_dict.items() if k.startswith('Date')]
['15th july']
49
Ashwini Chaudhary 14 Juni 2013 im 11:05

Sicher ist es möglich:

print next(val for key, val in my_dict.iteritems() if key.startswith('Date'))

Dies führt jedoch zu einem vollständigen Scan des Wörterbuchs. Es findet nur den ersten solchen passenden Schlüssel (wobei 'first' willkürlich ist) und löst StopIteration anstelle von KeyError aus, wenn keine Schlüssel übereinstimmen.

Um näher an das heranzukommen, woran Sie denken, ist es besser, dies als Funktion zu schreiben:

def value_by_key_prefix(d, partial):
    matches = [val for key, val in d.iteritems() if key.startswith(partial)]
    if not matches:
        raise KeyError(partial)
    if len(matches) > 1:
        raise ValueError('{} matches more than one key'.format(partial))
    return matches[0]
3
Martijn Pieters 20 Juni 2013 im 13:31

Nicht die beste Lösung, kann verbessert werden (überschreiben getitem )

class mydict(dict):
    def __getitem__(self, value):
        keys = [k for k in self.keys() if value in k]
        key = keys[0] if keys else None
        return self.get(key)


my_dict = mydict({'name': 'Klauss', 'age': 26, 'Date of birth': '15th july'})
print(my_dict['Date'])# returns 15th july
5
Ali SAID OMAR 14 Juni 2013 im 11:24

Sie schlagen keine kohärente API vor:

  1. Was sollte das Ergebnis von my_dict[''] sein? Sie haben keine Eins-zu-Eins-Zuordnung.
  2. Wie soll es auf andere Typen als str erweitert werden?

Ein weiterer Grund, warum Sie es nicht direkt haben können, selbst für Zeichenfolgen und unter der Annahme, dass Sie immer eine Liste zurückgeben, ist, dass Pythons dict mithilfe einer Hash-Tabelle implementiert wird und xy und {{X2} zugeordnet werden. } zu nicht verwandten Zellen in der Tabelle.

Wenn Sie also in die andere Richtung gehen: Eine solche Suche nach würde bedeuten, dass Sie eine langsamere Implementierung von dict anstreben (was keinen Sinn macht und für eine ungewöhnliche Verwendung optimiert) oder so langsam wie ein vollständiger Scan sind - was Sie tun kann es auch von Hand schreiben, da es nicht so üblich ist, eine dedizierte Komfortmethode wert zu sein.

0
Saullo G. P. Castro 8 Mai 2014 im 19:57

Mit der integrierten Filterfunktion können Sie Wörterbücher, Listen usw. basierend auf bestimmten Bedingungen filtern.

filtered_dict = dict(filter(lambda item: "Date" in item[0], my_dict.items()))

Der Vorteil ist, dass Sie es für verschiedene Datenstrukturen verwenden können.

1
Yogesh Kate 18 Apr. 2019 im 05:01

Es gibt eine nette und clevere Implementierung eines 'Fuzzy'-Wörterbuchs in Pywinauto - dies könnte perfekt für das sein, was Sie hier brauchen.

https://code.google.com/p/pywinauto/source/browse/pywinauto/fuzzydict.py

Und Dokumente hier: http://pywinauto.googlecode.com/hg/pywinauto/docs /code/pywinauto.fuzzydict.html

(Bearbeiten: Wenn Sie jedoch speziell vom Anfang des Schlüssels aus übereinstimmen möchten, müssen Sie möglicherweise die SequenceMatcher-Logik durch Ihren benutzerdefinierten Code ersetzen.)

0
formiaczek 14 Juni 2013 im 11:56
>>> my_dict = {'name': 'Klauss', 'age': 26, 'Date of birth': '15th july'}
>>> next(v for k,v in my_dict.items() if 'Date' in k)
'15th july'


>>> [ v for k,v in my_dict.items() if 'Date' in k]
['15th july']


>>> next( v for k,v in my_dict.items() if k.startswith('Date'))
'15th july'
>>> [ v for k,v in my_dict.items() if k.startswith('Date')]
['15th july']

Wenn ich die oben angegebene Methode verwende, erhalte ich eine StopIteration-Ausnahme

1
Ani Menon 30 Mai 2016 im 08:39