Accessing Python dict values with the key start characters

后端 未结 7 1494
南笙
南笙 2020-12-28 13:56

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:



        
相关标签:
7条回答
  • 2020-12-28 14:02

    You can't do such directly with dict[keyword], you've 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']
    
    0 讨论(0)
  • 2020-12-28 14:02

    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.

    0 讨论(0)
  • 2020-12-28 14:03

    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]
    
    0 讨论(0)
  • 2020-12-28 14:04

    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)

    0 讨论(0)
  • 2020-12-28 14:09

    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
    
    0 讨论(0)
  • 2020-12-28 14:10

    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.

    0 讨论(0)
提交回复
热议问题