【问题标题】:How can I build a Python case-insensitive set? [duplicate]如何构建 Python 不区分大小写的集合? [复制]
【发布时间】:2020-04-01 22:37:17
【问题描述】:

我正在使用 Python 3.7。如何构建一个 set(),其元素是字符串,不区分大小写?也就是说,如果我尝试了这些操作...

s = caseInsensitiveSet()
s.add("ABC")
s.add("abc")

结果将是一组大小为 one 的集合,其中包含唯一的元素“ABC”。

【问题讨论】:

  • 您将失去其原始形式的状态。
  • 请在问题中阐明该要求。
  • 你真的想要一个集合,其中"abc" in s"ABC" in s 都为真,不管"abc""ABC" 是集合中的实际元素吗?
  • 这很棘手,因为该集合并不能真正控制两个值如何被视为相等;这取决于所存储的项目。您需要定义一个新的字符串类型,它在计算哈希值和比较两个字符串是否相等时忽略大小写,或者定义一个全新的集合类型,它只适用于字符串并负责哈希本身。

标签: python-3.x string set case-insensitive


【解决方案1】:

只需覆盖您集合的add 方法。

from collections import MutableSet


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

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

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

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

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

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

例如:

In [1]: from caseinsensite import CasePreservingSet                                                                                                            

In [2]: s = CasePreservingSet()                                                                                                                                

In [3]: s.add("ABC")                                                                                                                                           

In [4]: s.add("abc")                                                                                                                                           

In [5]: list(s)                                                                                                                                                
Out[5]: ['abc']

In [6]: len(s)                                                                                                                                                 
Out[6]: 1

如果您想保留第一个输入元素的大小写,请改用此添加方法:

    def add(self, value):
        if self._fold(value) not in self._values:
            self._values[self._fold(value)] = value

例如:

In [1]: from caseinsensite import CasePreservingSet                                                                                                            

In [2]: s = CasePreservingSet()                                                                                                                                

In [3]: s.add("ABC")                                                                                                                                           

In [4]: s.add("aBc")                                                                                                                                           

In [5]: list(s)                                                                                                                                                
Out[5]: ['ABC']

改编自https://stackoverflow.com/a/27531275/8135079

【讨论】:

  • 感谢此代码。我将这个文件放在我的项目中的什么位置?
  • stackoverflow.com/questions/2349991/… 或者您可以将代码放在文件顶部您需要的地方。
  • 这应该是评论而不是答案。不要重复其他问题的全部答案。如果这是一个重复的问题,那么vote to close 和/或在您earn 足够reputation 后发表评论。如果问题不是重复的,请edit 发帖并针对这个特定问题定制答案。
  • 是的,这就是你复制的我的答案(你只删除了 Python 2 兼容层);大概您是通过在问题的评论中添加的链接 wim 找到的?要获得赏金,您通常会做更多,而不仅仅是接受其他人已经完成的工作。
  • 这就是我所做的。我提供了一种方法来保存第一个输入的案例或最后一个。
【解决方案2】:

也许只使用字典?

s = {}
s.setdefault("ABC".lower(), "ABC")
s.setdefault("abc".lower(), "abc")
s.values()
# equivalent to {'ABC'}

如果你愿意,可以编写一个包装类,然后你就可以参加比赛了。

【讨论】:

  • 这比s.add("ABC".upper())s.add("abc".upper()) 好在哪里?
  • @chepner 它记得第一次看到的套管,这似乎很重要,因为提问者明确指出了它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-19
  • 2013-07-07
  • 2019-09-03
  • 1970-01-01
  • 1970-01-01
  • 2021-04-12
  • 2013-08-19
相关资源
最近更新 更多