如何获得Case Insensitive Python SET

时间:2014-12-17 17:19:26

标签: python

我有一个字符串列表:

In [53]: l = ['#Trending', '#Trending', '#TrendinG', '#Yax', '#YAX', '#Yax']

In [54]: set(l)
Out[54]: {'#TrendinG', '#Trending', '#YAX', '#Yax'}

我希望此列表中包含不区分大小写的 set

预期结果:

Out[55]: {'#Trending', '#Yax'}

我怎样才能做到这一点?

6 个答案:

答案 0 :(得分:11)

如果您需要保留案例,则可以使用字典。小写键,然后提取值:

 {v.lower(): v for v in l}.values()

您可以将其封装到一个类中。

如果你不关心保留案例,只需使用一套:

{v.lower() for v in l}

演示:

>>> l = ['#Trending', '#Trending', '#TrendinG', '#Yax', '#YAX', '#Yax']
>>> {v.lower(): v for v in l}.values()
['#TrendinG', '#Yax']
>>> {v.lower() for v in l}
set(['#trending', '#yax'])

将第一种方法包装成类似乎:

try:
    # Python 3
    from collections.abc import MutableSet
except ImportError:
    # Python 2
    from collections import MutableSet

class CasePreservingSet(MutableSet):
    def __init__(self, *values):
        self._values = {}
        for v in values:
            self.add(v)

    def __repr__(self):
        return '<{}{} at {:x}>'.format(
            type(self).__name__, tuple(self._values.values()), id(self))

    def __contains__(self, value):
        return value.lower() in self._values

    def __iter__(self):
        try:
            # Python 2
            return self._values.itervalues()
        except AttributeError:
            # Python 3
            return iter(self._values.values())

    def __len__(self):
        return len(self._values)

    def add(self, value):
        self._values[value.lower()] = value

    def discard(self, value):
        try:
            del self._values[value.lower()]
        except KeyError:
            pass

用法演示:

>>> cps = CasePreservingSet(*l)
>>> cps
<CasePreservingSet('#TrendinG', '#Yax') at 1047ba290>
>>> '#treNdinG' in cps
True

答案 1 :(得分:3)

您可以使用lower()

>>> set(i.lower() for i in l)
set(['#trending', '#yax'])

答案 2 :(得分:2)

您可以在创建集合之前将整个列表转换为小写。

l = map(lambda s: s.lower(), l)
set(l)

答案 3 :(得分:2)

创建一个不区分大小写的set类。

class CaseInsensitiveSet(set):

    def add(self, item):
         try:
             set.add(self, item.lower())
         except Exception:                # not a string
             set.add(self, item)

    def __contains__(self, item):
        try:
            return set.__contains__(self, item.lower())
        except Exception:
            return set.__contains__(self, item)

    # and so on... other methods will need to be overridden for full functionality

答案 4 :(得分:1)

即使每个答案都使用.lower(),您所需的输出也会大写。

要实现它,你可以这样做:

l = ['#Trending', '#Trending', '#TrendinG', '#Yax', '#YAX', '#Yax']
l = set(i[0]+i[1:].capitalize() for i in l)
print l

输出:

set(['#Trending', '#Yax'])

答案 5 :(得分:0)

另一种选择是与multidict库中的istr(不区分大小写的str)对象一起使用:

In [1]: from multidict import istr, CIMultiDict                                                                                                               

In [2]: s = {'user-agent'}                                                                                                                                    

In [5]: s = CIMultiDict({istr(k): None for k in {'user-agent'}})                                                                                              

In [6]: s                                                                                                                                                     
Out[6]: <CIMultiDict('User-Agent': None)>

In [7]: 'user-agent' in s                                                                                                                                     
Out[7]: True

In [8]: 'USER-AGENT' in s                                                                                                                                     
Out[8]: True