Test if set is a subset, considering the number (multiplicity) of each element in the set

前端 未结 5 1893
谎友^
谎友^ 2020-12-19 14:32

I know I can test if set1 is a subset of set2 with:

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

But the following is a

相关标签:
5条回答
  • 2020-12-19 14:51

    The short answer to your question is there is no set operation that does this, because the definition of a set does not provide those operations. IE defining the functionality you're looking for would make the data type not a set.

    Sets by definition have unique, unordered, members:

    >>> print {'a', 'a', 'b', 'c'}
    set(['a', 'c', 'b'])
    >>> {'a', 'a', 'b', 'c'} == {'a', 'b', 'c'}
    True
    
    0 讨论(0)
  • 2020-12-19 14:51

    For those that are interested in the usual notion of multiset inclusion, the easiest way to test for multiset inclusion is to use intersection of multisets:

    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
    

    This is a standard idea used in idempotent semirings.

    0 讨论(0)
  • 2020-12-19 14:54

    Combining previous answers gives a solution which is as clean and fast as possible:

    def issubset(X, Y):
        return all(v <= Y[k] for k, v in X.items())
    
    • No instances created instead of 3 in @A.Rodas version (both arguments must already be of type Counter, since this is the Pythonic way to handle multisets).
    • Early return (short-circuit) as soon as predicate is falsified.
    0 讨论(0)
  • 2020-12-19 15:04

    As @DSM deleted his solution , I will take the opportunity to provide a prototype based on which you can expand

    >>> 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
    >>> 
    
    0 讨论(0)
  • 2020-12-19 15:08

    As stated in the comments, a possible solution using Counter:

    from collections import Counter
    
    def issubset(X, Y):
        return len(Counter(X)-Counter(Y)) == 0
    
    0 讨论(0)
提交回复
热议问题