【问题标题】:Test if set is a subset, considering the number (multiplicity) of each element in the set测试集合是否是子集,考虑集合中每个元素的数量(多重性)
【发布时间】:2013-02-18 22:38:10
【问题描述】:

我知道我可以测试 set1 是否是 set2 的子集:

{'a','b','c'} <= {'a','b','c','d','e'} # True

但以下也是正确的:

{'a','a','b','c'} <= {'a','b','c','d','e'} # True

我如何让它考虑集合中元素出现的次数,以便:

{'a','b','c'}     <= {'a','b','c','d','e'}      # True
{'a','a','b','c'} <= {'a','b','c','d','e'}      # False since 'a' is in set1 twice but set2 only once
{'a','a','b','c'} <= {'a','a','b','c','d','e'}  # True because both sets have two 'a' elements

我知道我可以这样做:

A, B, C = ['a','a','b','c'], ['a','b','c','d','e'], ['a','a','b','c','d','e']
all([A.count(i) == B.count(i) for i in A]) # False
all([A.count(i) == C.count(i) for i in A]) # True

但我想知道是否有更简洁的内容,例如 set(A).issubset(B,count=True) 或避免列表推导的方法。谢谢!

【问题讨论】:

  • {'a','a','b','c'}{'a','b','c'}完全相同。这就是集合的意义。
  • 在 Python 中,set 不能有重复项。你可能不想使用collection.Counter,它可以被认为是一个多重集合
  • 您是在寻找多组吗?然后使用collections.Counter()
  • 计数器不这样做,因为Counter('aabc') &lt;= Counter('aaabcd') 给出了 True,但 Counter('abce') &lt;= Counter('aabcd') 也是如此。第二个字符串中显然没有'e'。

标签: python set subset multiset multiplicity


【解决方案1】:

对您的问题的简短回答是没有设置操作可以执行此操作,因为definition of a set 不提供这些操作。 IE 定义您正在寻找的功能将使数据类型不是一个集合。

根据定义,集合具有唯一的、无序的成员:

>>> print {'a', 'a', 'b', 'c'}
set(['a', 'c', 'b'])
>>> {'a', 'a', 'b', 'c'} == {'a', 'b', 'c'}
True

【讨论】:

  • 那么,如果我要测试字符串中的字符,有没有办法测试 string2 中每个 string1 字符的成员资格,同时考虑到它出现的次数?这里有没有从列表推导中逃脱?
  • 我不确定您所说的“考虑到它发生的次数”是什么意思。你的意思是如果'a'在string1中出现x次,那么'a'应该在string2中出现> x次?列表推导是 Python 语言的关键部分。拥抱它们 :) (如果你不理解它们,可以先将它们写成 for 循环)
【解决方案2】:

由于@DSM删除了他的解决方案,我将借此机会提供一个原型,您可以在此基础上扩展

>>> class Multi_set(Counter):
    def __le__(self, rhs):
        return all(v == rhs[k] for k,v in self.items())


>>> Multi_set(['a','b','c']) <= Multi_set(['a','b','c','d','e'])
True
>>> Multi_set(['a','a','b','c']) <= Multi_set(['a','b','c','d','e'])
False
>>> Multi_set(['a','a','b','c']) <= Multi_set(['a','a','b','c','d','e'])
True
>>> 

【讨论】:

  • == 似乎与 __le__ 不匹配?
  • 在我看来应该是&lt;=而不是==
  • 这不是多重集&lt;=。那将是all(v &lt;= rhs[k] for k,v in self.items())
【解决方案3】:

如 cmets 中所述,使用Counter 的可能解决方案:

from collections import Counter

def issubset(X, Y):
    return len(Counter(X)-Counter(Y)) == 0

【讨论】:

  • 这是最好的答案。它很简单,不需要创建第二个类。
【解决方案4】:

结合以前的答案可以提供尽可能干净和快速的解决方案:

def issubset(X, Y):
    return all(v <= Y[k] for k, v in X.items())
  • 在@A.Rodas 版本中没有创建实例而不是 3(两个参数必须已经是 Counter 类型,因为这是处理多重集的 Pythonic 方式)。
  • 一旦谓词被伪造就提前返回(短路)。

【讨论】:

    【解决方案5】:

    对于那些对多集包含的通常概念感兴趣的人,测试多集包含的最简单方法是使用多集的交集:

    from collections import Counter
    
    def issubset(X, Y):
        return X & Y == X
    
    issubset(Counter("ab"), Counter("aab"))  # returns True
    issubset(Counter("abc"), Counter("aab")) # returns False
    

    这是idempotent semirings中使用的标准思想。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-23
      • 2014-05-13
      • 2018-09-09
      • 1970-01-01
      • 2021-04-05
      • 2011-10-28
      相关资源
      最近更新 更多