Python中集合的不区分大小写的比较

时间:2009-09-25 23:35:12

标签: python django compare

我有两套(虽然我可以做清单,或者其他):

a = frozenset(('Today','I','am','fine'))
b = frozenset(('hello','how','are','you','today'))

我想得到:

frozenset(['Today'])

或至少:

frozenset(['today'])

如果我小写我认为的所有内容,第二个选项是可行的,但我正在寻找一种更优雅的方式。是否可以

a.intersection(b) 

以不区分大小写的方式?

Django中的快捷方式也很好,因为我正在使用该框架。

下面的交集方法示例(我无法弄清楚如何在评论中对其进行格式化):

print intersection('Today I am fine tomorrow'.split(),
                    'Hello How a re you TODAY and today and Today and Tomorrow'.split(),
                    key=str.lower)

[(['tomorrow'], ['Tomorrow']), (['Today'], ['TODAY', 'today', 'Today'])]

4 个答案:

答案 0 :(得分:9)

这里的版本适用于任何一对迭代:

def intersection(iterableA, iterableB, key=lambda x: x):
    """Return the intersection of two iterables with respect to `key` function.

    """
    def unify(iterable):
        d = {}
        for item in iterable:
            d.setdefault(key(item), []).append(item)
        return d

    A, B = unify(iterableA), unify(iterableB)

    return [(A[k], B[k]) for k in A if k in B]

示例:

print intersection('Today I am fine'.split(),
                   'Hello How a re you TODAY'.split(),
                   key=str.lower)
# -> [(['Today'], ['TODAY'])]

答案 1 :(得分:7)

不幸的是,即使您可以“随时更改”套装'项目(__lt__和朋友 - 的比较相关特殊方法 - 实际上,只有__eq__需要当前套装的方式实现,但这是一个实现细节) - 你不能,因为它们属于内置类型,str - 这是不够的,因为__hash__ 关键当您想要进行交叉时,它已经被应用了,将这些项目放在不同的散列桶中,从那里他们需要最终使交叉点工作你想要的方式(即,不能保证'今天'和'今天'在同一个桶里。)

因此,出于您的目的,您不可避免地需要构建新的数据结构 - 如果您认为它根本不是“不优雅”,那么您很幸运:内置集合不会随身携带巨大的行李和开销,允许人们改变比较和散列函数,这将使事情膨胀10倍(或更多),以满足(可能)一百万个用例的需求。

如果您经常需要使用不区分大小写的比较,则应考虑子类化或包装str(重写比较和散列)以提供“不区分大小写的str”类型cistr - 然后当然,请确保只有cistr的实例(例如)被添加到您感兴趣的集合(& c)中(通过子类化set& c,或者仅仅通过小心谨慎)。举一个过于简单的例子......:

class ci(str):
  def __hash__(self):
    return hash(self.lower())
  def __eq__(self, other):
    return self.lower() == other.lower()

class cifrozenset(frozenset):
  def __new__(cls, seq=()):
    return frozenset((ci(x) for x in seq))

a = cifrozenset(('Today','I','am','fine'))
b = cifrozenset(('hello','how','are','you','today'))

print a.intersection(b)

根据您表达的愿望,这会释放frozenset(['Today'])。当然,在现实生活中,你可能想要做更多的覆盖(例如......:我在这里有事情的方式,cifrozenset上的任何操作都返回普通frozenset,失去了珍贵的案例独立特殊功能 - 您可能希望确保每次都返回cifrozenset,并且虽然非常可行,但这并非无足轻重。)

答案 2 :(得分:3)

首先,你的意思是a.intersection(b)吗?交集(如果不区分大小写)将为set(['today'])。区别在于set(['i', 'am', 'fine'])

以下是两个想法:

1。)编写一个函数将两个元素的元素转换为小写,然后进行交集。这是你可以做到的一种方式:

>>> intersect_with_key = lambda s1, s2, key=lambda i: i: set(map(key, s1)).intersection(map(key, s2))
>>> fs1 = frozenset('Today I am fine'.split())
>>> fs2 = frozenset('Hello how are you TODAY'.split())
>>> intersect_with_key(fs1, fs2)
set([])
>>> intersect_with_key(fs1, fs2, key=str.lower)
set(['today'])
>>>

这不是很有效,因为必须在每次调用时创建转换和新集。

2.。)扩展frozenset类以保持元素的不区分大小写的副本。重写intersection方法以使用不区分大小写的元素副本。这会更有效率。

答案 3 :(得分:1)

>>> a_, b_ = map(set, [map(str.lower, a), map(str.lower, b)])
>>> a_ & b_
set(['today'])

或者......用较少的地图,

>>> a_ = set(map(str.lower, a))
>>> b_ = set(map(str.lower, b))
>>> a_ & b_
set(['today'])