python中的集合不区分大小写

python中的集合不区分大小写,python,set,case,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

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

例如,我有以下列表:

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()
我会得到列表,但是名称是小写/大写的

我只想消除“重复”,而不考虑区分大小写的方法

非常感谢你的帮助


谢谢

改用散列,我认为用集合无法轻松实现这一点

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

用散列代替,我不认为你能用集合轻松地做到这一点

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

您可以使用集合跟踪值的
.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']

您可以使用集合跟踪值的
.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']

如果你想按规则玩,我能想到的最好的解决办法是有点混乱,使用集合来跟踪出现的单词

seen_words = set()
L1 = []
for word in L0:
    if word.lower() not in seen_words:
        L1.append(word)
        seen_words.add(word.lower())
如果你想变得更黑客,有一个更优雅的解决方案,你可以使用字典来跟踪哪些单词已经被看到,这几乎是一行

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

如果你想按规则玩,我能想到的最好的解决办法是有点混乱,使用集合来跟踪出现的单词

seen_words = set()
L1 = []
for word in L0:
    if word.lower() not in seen_words:
        L1.append(word)
        seen_words.add(word.lower())
如果你想变得更黑客,有一个更优雅的解决方案,你可以使用字典来跟踪哪些单词已经被看到,这几乎是一行

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

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

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

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

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

该死的击败我;)该死的,比我快;)谢谢大家的回答!我认为这是编码量最低的一个。它可能是编码量最低的一个,但正如@PM2Ring所指出的,这也是错误的,因为你说“只保留第一个找到的”。这将保留最后找到的。@Tomwylie代码已被更新以向后扫描源代码列表,因此现在它达到了预期目标。谢谢大家的回答!我认为这是编码量最低的一个。它可能是编码量最低的一个,但正如@PM2Ring所指出的,这也是错误的,因为你说“只保留第一个找到的”。这将保留最后找到的内容。@Tomwylie代码已经更新,可以向后扫描源列表,因此现在它达到了预期的目标。可爱,尽管有些人不赞成你对列表的理解,但会产生副作用(变异
所见单词
)。。。或者使用dict而不是set,这样您就可以使用list comp而不是“传统”for循环来执行此操作我最初有一个基于集合的解决方案,但正如您指出的,这里肯定有一个折衷方案,毫无疑问,在我看来,第二个解决方案更优雅,但更粗糙。我可能会将两者都包括在内,并让OP选择。当然,第一个版本更长,但它使用更少的内存,并且没有令人讨厌的副作用,所以我将它归类为更具Pythonic的版本。@Tom wylie-谢谢。这个解决方案也非常优雅。并且确实保留了遇到的第一个值。谢谢。很可爱,虽然有些人不赞成你的列表理解,但会有副作用(变异
seen\u words
)。。。或者使用dict而不是set,这样您就可以使用list comp而不是“传统”for循环来执行此操作我最初有一个基于集合的解决方案,但正如您指出的,这里肯定有一个折衷方案,毫无疑问,在我看来,第二个解决方案更优雅,但更粗糙。我可能会将两者都包括在内,并让OP选择。当然,第一个版本更长,但它使用更少的内存,并且没有令人讨厌的副作用,所以我将它归类为更具Pythonic的版本。@Tom wylie-谢谢。这个解决方案也非常优雅。并且确实保留了遇到的第一个值。谢谢。这是你们指出的OP的过度使用,但对其他人可能非常有用。:)正如您所指出的,这对OP来说是一种过度的杀伤力,但对其他人来说可能非常有用。:)