定义字典成员资格比较而不重载IN?

时间:2016-04-14 16:09:23

标签: python

所以我有一个值列表:

alist = list()

我想查看列表中的成员是否在dict中:

ahash = dict() #imagine I have filled a dictionary with data. 

for member in alist: 
     if member in hash:
        #DO STUFF 

这很简单。

然而,我想要做的是重新定义IN以实现模糊比较。所以我想做的是将FOOBARBAZZ之类的东西与*匹配,使得FOO *匹配FOOBARBAZZ。

我能想到的最简单的方法是将这整个情境实现为对象中的方法,然后重载IN运算符。但是出于我自己的原因(完全迂腐),我想避免使用OOP方法。

没有为每个比较循环遍历整个Dictionary(这听起来不对!)如何实现我对Dictionaries的自定义比较?

额外: IN运算符除IN之外是否有不同的名称?该命名使得关于运营商的信息难以在搜索引擎中进行研究。我认为它可能与__contains__相同,但我还没有想到__contains__如何为字典工作。

3 个答案:

答案 0 :(得分:3)

要覆盖in,您可以对内置dict类型进行子类化,并定义新的__contains__方法(这是in在幕后调用的方法):

In [9]: class FuzzyDict(dict):
   ...:     def __contains__(self, needle):
   ...:         if '*' not in needle:
   ...:             return super(FuzzyDict, self).__contains__(needle)
   ...:         else:
   ...:             for key in self.keys():
   ...:                 if str(key).startswith(needle[:-1]):
   ...:                     return True
   ...:             return False
   ...:

这在大多数情况下都像dict

In [12]: my_dict = FuzzyDict(zip('abcde', range(1, 6)))

In [13]: my_dict
Out[13]: {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

In [14]: my_dict['apple'] = 6

直到您开始使用in测试:

In [15]: 'a' in my_dict
Out[15]: True

In [16]: 'a*' in my_dict
Out[16]: True

In [17]: 'ap*' in my_dict
Out[17]: True

In [18]: 'b*' in my_dict
Out[18]: True

In [19]: 'bi*' in my_dict
Out[19]: False

这是基于我在帖子中看到的内容。如果您需要支持超过foo*,那么显然startswith测试是不够的,您甚至可能必须使用正则表达式。这也只会覆盖in - 如果您想要my_dict['FOO*']之类的密钥访问权限,则还需要覆盖__getitem__和朋友。

根据您的要求,我认为不能在O(n)以内完成此操作。 dicts O(1)访问时间的唯一原因是因为散列,并且在没有整个密钥的情况下无法获取散列。

答案 1 :(得分:1)

回答这个问题的最佳方法是将你想要“模糊匹配”的任何东西翻译成正则表达式。然后,您可以将正则表达式应用于dict.keys(),示例可能在此处:

How to use re match objects in a list comprehension

是否已经为您的模糊匹配定义了正式语言,或者您正在制作一种语言?将“foo *”变成re可以通过

来完成
regex = re.sub("\*", ".*", list_element) + "$"

如果尾随'*'是您用于匹配的唯一符号,那么您的解决方案将是:

for member in alist:
   regex = re.sub("\*", ".*", member) + "$"
   if any([re.match(regex, x) for x in hash.keys()]):
     # do stuff

如果你想让你的匹配语言更强大,你只需要将你的翻译变成一个更复杂的正则表达式。

答案 2 :(得分:1)

至少有两种方法可以实现目标。在示例A 中,运行快速查询以确定您的成员是否是哈希的一部分。一找到匹配就会停止。另一方面,由于返回了所有匹配值,因此示例B 可能会更有用。这允许您处理与您的成员打交道的那部分哈希,而不必运行另一个查询。

#! /usr/bin/env python3


def main():
    """Demonstrate the usage of dict_contains and dict_search."""
    my_list = ['ist', 'out', 'ear', 'loopy']
    my_hash = {'a': 50, 'across': 14, 'ahash': 12, 'alist': 31, 'an': 73,
               'and': 11, 'are': 2, 'as': 34, 'avoid': 82, 'be': 3,
               'besides': 49, 'but': 45, 'can': 32, 'check': 51, 'come': 84,
               'comparison': 40, 'custom': 61, 'dictionary': 58,
               'different': 76, 'difficult': 85, 'do': 86, 'does': 13,
               'entire': 37, 'every': 33, 'filled': 77, 'foobarbazz': 20,
               'for': 42, 'fuzzy': 53, 'have': 30, 'how': 36, 'however': 68,
               'i': 74, 'if': 43, 'implement': 62, 'in': 57, 'information': 46,
               'is': 71, 'it': 83, 'like': 64, 'list': 55, 'looping': 70,
               'makes': 63, 'match': 16, 'matches': 1, 'member': 29,
               'members': 78, 'method': 7, 'might': 6, 'most': 28, 'my': 38,
               'name': 18, 'naming': 41, 'of': 52, 'on': 17, 'oop': 35,
               'operator': 21, 'over': 19, 'overload': 27, 'own': 72,
               'reasons': 79, 'redefine': 10, 'research': 22, 'same': 48,
               'search': 75, 'see': 5, 'situation': 39, 'so': 87, 'sounds': 24,
               'straightforward': 69, 'stuff': 15, 'such': 66, 'that': 47,
               'the': 56, 'then': 54, 'things': 81, 'think': 67, 'this': 59,
               'to': 9, 'very': 0, 'want': 23, 'way': 60, 'what': 44,
               'whole': 26, 'with': 8, 'without': 65, 'works': 4, 'would': 25,
               'yet': 80}
    # Example A
    for member in my_list:
        if dict_contains(my_hash, member):
            print('Found:', member)
    # Example B
    for member in my_list:
        match = dict_search(my_hash, member)
        if match:
            print('Query with', member, 'resulted in', match)
        else:
            print('Searching with', member, 'failed miserably')


def dict_contains(self, needle):
    """Check if search term can be found in any key of the given dict."""
    return any(needle in haystack for haystack in self)


def dict_search(self, pattern):
    """Return the dict's subset where the search term is found in the key."""
    return {key: value for key, value in self.items() if pattern in key}


if __name__ == '__main__':
    main()