Roman Rdgz
Roman Rdgz

Reputation: 13264

Accessing Python dict values with the key start characters

I was wondering: would it be possible to access dict values with uncomplete keys (as long as there are not more than one entry for a given string)? For example:

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

Is this possible? How could it be done?

Upvotes: 51

Views: 84817

Answers (7)

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 251116

You can't do such directly with dict[keyword]. You have to iterate through the dict and match each key against the keyword and return the corresponding value if the keyword is found. This is going to be an O(N) operation.

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

To get all such values use a list comprehension:

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

use str.startswith if you want only those values whose keys starts with 'Date':

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

Upvotes: 85

Yogesh Kate
Yogesh Kate

Reputation: 317

You can use the built-in filter function to filter dictionaries, lists, etc. based on specific conditions.

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

The advantage is that you can use it for different data structures.

Upvotes: 7

saurabh
saurabh

Reputation: 31

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

if i use the above given method i am getting StopIteration exception

Upvotes: 3

Elazar
Elazar

Reputation: 21645

You are not suggesting a coherent API:

  1. What should be the result of my_dict['']? You don't have a one-to-one mapping.
  2. How is it supposed to be extended to types other than str?

Another reason you can't have it directly, even for strings and assuming you always return a list, is because Python's dict is implemented using a hash table, and it will map xy and xz to unrelated cells in the table.

So, going the other way: such a lookup to would mean going for a slower implementation of dict, (which doesn't make sense, optimizing for an uncommon use) or being as slower as a full scan - which you may as well write it by hand, as it is not that common to be worth a dedicated convenience method.

Upvotes: 2

Martijn Pieters
Martijn Pieters

Reputation: 1124090

Sure it is possible:

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

but this incurs a full scan through the dictionary. It only finds the first such matching key (where 'first' is arbitrary) and raises StopIteration instead of KeyError if no keys match.

To get closer to what you are thinking of, it's better to write this as a function:

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]

Upvotes: 7

formiaczek
formiaczek

Reputation: 425

There's a nice and clever implementation of a 'fuzzy' dictionary in pywinauto - this might be perfect for what you need here.

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

and docs here: http://pywinauto.googlecode.com/hg/pywinauto/docs/code/pywinauto.fuzzydict.html

(edit: although if you specifically want to match from the beginning of the key, you might need to replace SequenceMatcher logic with your custom code)

Upvotes: 0

Ali SAID OMAR
Ali SAID OMAR

Reputation: 6792

not the best solution, can be improved (overide 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

Upvotes: 10

Related Questions