代码之家  ›  专栏  ›  技术社区  ›  Adam Nelson

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

  •  4
  • Adam Nelson  · 技术社区  · 17 年前

    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 回复  |  直到 17 年前
        1
  •  10
  •   jfs    17 年前

    以下是适用于任何一对iterables的版本:

    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'])]
    
        2
  •  8
  •   Alex Martelli    17 年前

    不幸的是,即使您可以“动态更改”集合项的比较相关特殊方法( __lt__ 还有朋友——事实上,只是 __eq__ 需要当前实现集合的方式,但这是一个实现细节)——您不能,因为它们属于内置类型, str --这还不够,因为 __hash__ 而且 关键的 和 当您想要进行交集时,它已经被应用,将集合的项放在不同的散列桶中,从它们需要结束的地方开始,使交集以您想要的方式工作(即,不保证“今天”和“今天”在同一个桶中)。

    如果您经常需要与不区分大小写的比较连接,则应该考虑子类或包装。 str (重写比较和哈希)以提供“不区分大小写的str”类型 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 ,失去了宝贵的案例独立特性--您可能希望确保 相反,每次都返回,虽然非常可行,但这并不是微不足道的)。

        3
  •  4
  •   jfs    17 年前

    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 方法使用元素的不区分大小写副本。这样会更有效率。

        4
  •  2
  •   eric.frederich    17 年前
    >>> 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'])
    
    推荐文章