2013-06-14 5 views
12

Ich frage mich: Wäre es möglich, auf dict-Werte mit unvollständigen Schlüsseln zuzugreifen (solange es für eine gegebene Zeichenkette nicht mehr als einen Eintrag gibt)? Zum Beispiel:Zugriff auf Python-dict-Werte mit den Schlüsselanfangszeichen

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?

+0

Sie nee d Sprachen wie PERL oder ML dafür, als eine eingebaute Funktion. – Elazar

+0

Mir ist keine solche Funktion in Perl bekannt. – chepner

Antwort

26

Sie können dies nicht direkt mit dict[keyword] tun, müssen Sie durch das Diktat iterieren und jeden Schlüssel mit dem Schlüsselwort übereinstimmen 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 verwenden, um eine Liste Verständnis zu erhalten:

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

Verwendung str.startswith, wenn Sie nur die Werte, deren Schlüssel beginnt mit ‚Datum‘ wollen:

>>> 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'] 
3

Sicher, es ist möglich:

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

, aber dies führt zu einem vollständigen Scan durch das Wörterbuch. Es findet nur die erste solche passenden Schlüssel (wo "erste" ist beliebig) und erhöht StopIteration anstelle von KeyError, wenn keine Schlüssel übereinstimmen.

Um näher zu dem, was Sie denken an, es ist besser als eine 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] 
+1

Um noch näher zu kommen, möchten Sie vielleicht mit dieser Funktion 'dict' ableiten. Oder besser, reimplementieren Sie es mit einem Baum statt einem Hash. – Elazar

0

Sie sind eine kohärente API nicht darauf hindeutet:

  1. Was das Ergebnis sein sollte my_dict['']? Sie haben kein Eins-zu-eins-Mapping. Wie soll es auf andere Typen als str erweitert werden?

Ein weiterer Grund, warum Sie es nicht direkt haben, auch für Streicher und vorausgesetzt, Sie immer eine Liste zurückkehren, ist, weil Python dict implementiert wird eine Hash-Tabelle verwendet wird, und es wird xy und xz an unabhängige Zellen in der Karte Tabelle.

Also gehen Sie in die andere Richtung: so ein Nachschlagen würde bedeuten, für eine langsamere Implementierung von dict, (was macht keinen Sinn, für eine ungewöhnliche Verwendung optimieren) oder so langsam wie ein vollständiger Scan - was Sie kann es auch von Hand schreiben, wie es nicht ist, dass gemeinsam eine dedizierte Komfort-Methode wert ist.

4

nicht die beste Lösung, kann

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 
0

Es gibt eine schöne und kluge Umsetzung eines ‚Fuzzy‘ Wörterbuch in pywinauto ( overide getitem) verbessert werden - das ist für perfekt sein könnte, was Sie hier benötigen.

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

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

(edit: obwohl, wenn Sie speziell von Anfang an der Schlüssel passen wollen, müssen Sie möglicherweise SequenceMatcher Logik mit Ihrem eigenen Code ersetzen)

1
>>> 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 angegebenen Methode verwenden, ich bin immer StopIteration Ausnahme

Verwandte Themen