【问题标题】:Accessing Python dict values with the key start characters使用键开始字符访问 Python dict 值
【发布时间】:2013-06-14 10:52:24
【问题描述】:

我想知道:是否可以使用不完整的键访问 dict 值(只要给定字符串的条目不超过一个)?例如:

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

这可能吗?怎么可能?

【问题讨论】:

  • 您需要 PERL 或 ML 之类的语言作为内置功能。
  • 我不知道 Perl 中有任何此类功能。

标签: python dictionary


【解决方案1】:

您不能直接使用dict[keyword] 执行此操作,您必须遍历字典并将每个键与关键字匹配,如果找到关键字则返回相应的值。 这将是一个O(N) 操作。

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

如果您只想要键以“日期”开头的值,请使用 str.startswith

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

【讨论】:

    【解决方案2】:

    不是最好的解决方案,可以改进(覆盖 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
    

    【讨论】:

    • 好主意:也可以调整为使用正则表达式模式
    【解决方案3】:

    当然可以:

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

    但这会导致对字典进行全面扫描。它只找到 first 这样的匹配键(其中 'first' 是任意的),如果没有匹配的键,则引发 StopIteration 而不是 KeyError

    为了更接近你的想法,最好把它写成一个函数:

    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]
    

    【讨论】:

    • 为了更接近,您可能希望使用该函数对dict 进行子类化。或者更好的是,使用树而不是哈希重新实现它。
    【解决方案4】:

    您可以使用内置的过滤器功能,根据特定条件过滤字典、列表等。

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

    优点是你可以将它用于不同的数据结构。

    【讨论】:

      【解决方案5】:
      >>> 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']
      

      如果我使用上面给出的方法,我会得到 StopIteration 异常

      【讨论】:

        【解决方案6】:

        您并不是在建议一个连贯的 API:

        1. my_dict[''] 的结果应该是什么?您没有一对一的映射。
        2. 它应该如何扩展到str以外的类型?

        另一个你不能直接使用它的原因,即使对于字符串并且假设你总是返回一个列表,是因为 Python 的 dict 是使用哈希表实现的,它会将 xyxz 映射到不相关的表格中的单元格。

        所以,换一种方式:这样的查找意味着要更慢地实现dict,(这没有意义,针对不常见的用途进行优化)或者像完全扫描一样慢 - 这您也可以手动编写它,因为值得一个专门的便捷方法并不常见。

        【讨论】:

          【解决方案7】:

          在 pywinauto 中有一个“模糊”字典的漂亮而聪明的实现 - 这可能非常适合您在这里的需要。

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

          这里有文档: http://pywinauto.googlecode.com/hg/pywinauto/docs/code/pywinauto.fuzzydict.html

          (编辑:虽然如果您特别想从键的开头进行匹配,您可能需要用您的自定义代码替换 SequenceMatcher 逻辑)

          【讨论】:

            猜你喜欢
            • 2012-03-08
            • 1970-01-01
            • 2013-01-21
            • 2021-09-13
            • 2016-02-29
            • 2017-06-17
            • 1970-01-01
            • 1970-01-01
            • 2012-01-28
            相关资源
            最近更新 更多