对python中的集不区分大小写

时间:2017-07-14 14:48:02

标签: python set case

我有一个从多个列表生成的列表。此组合列表包含最终用户生成的名称。因此包含相似的名称,但具有不同的大写/小写字符。 我想过滤掉包含相同字符的名称,并保留原始列表中的第一个名称。

作为一个例子,我有以下列表:

L0 = ['A_B Cdef', 'A_B Cdef', 'A_B Cdef', 'A_B CdEF', 'A_B CDEF','a_B CdEF', 'A_b CDEF', 'GG_ooo', 'a1-23456']

如果我跑:

L1 = list(set(L0))

我明白了:

['a1-23456', 'A_B Cdef', 'A_B CdEF', 'A_B CDEF', 'a_B CdEF', 'A_b CDEF', 'GG_ooo']

我想保留第一个具有相同字符的名称。

所以我的结果是:

['a1-23456', 'A_B Cdef', 'GG_ooo']

如果我使用.lower().upper()我会获得列表,但名称是较低/较高的。

我只想消除"重复"不考虑区分大小写的方法。

非常感谢。

谢谢!

4 个答案:

答案 0 :(得分:3)

您可以使用集合跟踪值的.lower()版本,然后将原始值附加到新列表中,如果他们的.lower()版本已经不在集合中:

s = set()
L = []
for x in L0:
  if x.lower() not in s:
      s.add(x.lower())
      L.append(x)

print(L)
# ['A_B Cdef', 'GG_ooo', 'a1-23456']

答案 1 :(得分:2)

使用哈希代替,我不认为你可以用套装轻松完成。

L0 = {value.lower(): value for value in L0[::-1]}.values()

答案 2 :(得分:2)

你已经有了几个很好的答案,下面的代码对你的用例来说可能有些过分,但为了好玩,我创建了一个简单的不区分大小写的可变集合类。请注意,它保留了它找到的第一个字符串,而不是让它被后来的条目破坏。

import collections.abc

class CasefoldSet(collections.abc.MutableSet):
    def __init__(self, iterable=None):
        self.elements = {} 
        if iterable is not None:
            for v in iterable:
                self.add(v)

    def __contains__(self, value):
        return value.casefold() in self.elements

    def add(self, value):
        key = value.casefold()
        if key not in self.elements:
            self.elements[key] = value

    def discard(self, value):
        key = value.casefold()
        if key in self.elements:
            del self.elements[key]

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

    def __iter__(self):
        return iter(self.elements.values())

    def __repr__(self):
        return '{' + ', '.join(map(repr, self)) + '}'

# test

l0 = [
    'GG_ooo', 'A_B Cdef', 'A_B Cdef', 'A_B Cdef', 
    'A_B CdEF', 'A_B CDEF', 'a_B CdEF', 'A_b CDEF', 'a1-23456',
]

l1 = CasefoldSet(l0[:4])
print(l1)
l1 |= l0[4:]
print(l1)
l2 = {'a', 'b', 'A_B Cdef'} | l1
print(l2)
l3 = l2 & {'a', 'GG_ooo', 'a_B CdEF'}
print(l3)

<强>输出

{'GG_ooo', 'A_B Cdef'}
{'GG_ooo', 'A_B Cdef', 'a1-23456'}
{'GG_ooo', 'A_B Cdef', 'a1-23456', 'b', 'a'}
{'a_B CdEF', 'a', 'GG_ooo'}

此类继承了collections.abc.MutableSet中的各种有用方法,但为了使其成为set的完全替代方法,它确实需要更多方法。请注意,如果您尝试传递非字符串项,它将引发AttributeError

答案 3 :(得分:1)

如果您想遵守规则,我能想到的最佳解决方案有点乱,使用集合来跟踪出现的单词;

seen_words = set()
L1 = []
for word in L0:
    if word.lower() not in seen_words:
        L1.append(word)
        seen_words.add(word.lower())

如果你想得到一点点hackier有一个更优雅的解决方案,你可以使用字典来跟踪已经看过哪些单词,而且它几乎只有一行;

seen_words = {}
L1 = [seen_words.setdefault(word.lower(), word) 
      for word in L0 if word.lower() not in seen_words]
print(L1)

两种解决方案都输出相同的结果;

['A_B Cdef', 'GG_ooo', 'a1-23456']