在Python中,如何检查一组项目是否仅属于两个列表中的一个?

2 投票
3 回答
3979 浏览
提问于 2025-04-18 05:43

我有两个列表,里面的东西是互不相容的——我们可以用油和水来举例,因为这两种东西是不能混合在一起的:

waters = ['tea', 'lemonade', 'juice', 'pepsi']
oils = ['olive oil', 'corn oil', 'peanut oil']

我想检查一下,foo这个列表里是否只包含水列表或油列表里的东西,但不能同时包含这两种。也就是说:

foo = ['tea', 'corn oil'] => FAIL
bar = ['pepsi', 'tea', 'juice'] => PASS
baz = ['olive oil'] => PASS

我到目前为止的尝试:

def contains_conflicting_types(test, targets, conflicts):
    intarget = False
    inconflict = False
    for t in test:
        if t in targets:
            intarget = True
        if t in conflicts:
            inconflict = True
        if intarget and inconflict:
            return True
    return False

#Usage:
contains_conflicting_types(['A','B'], ['A','1'], ['B','2']) #returns True A and B are in conflict

不用说,这个方法看起来很糟糕,但能用?我该怎么做得更好呢?

3 个回答

2

给定要比较的两个集合

waters = frozenset(['tea', 'lemonade', 'juice', 'pepsi'])
oils = frozenset(['olive oil', 'corn oil', 'peanut oil'])

还有一个测试组

foo = frozenset(['tea', 'corn oil'])

你可以通过检查这两个集合是否是不相交的(也就是说它们的交集是空的),来判断这个集合是否只包含来自一个组的项目(使用异或运算符)。

foo.isdisjoint(waters) ^ foo.isdisjoint(oils)

对于Python 2.5及更早版本,可以使用:

bool(foo.intersection(waters)) ^ bool(foo.intersection(oils))

另外,如果你记得&是两个集合的交集运算符。因为可读性很重要,如果你或者其他维护你代码的人不确定&这个符号的意思,最好用s1.intersection(s2)来表示。

bool(foo & waters) ^ bool(foo & oils)
2

一个简单的一行代码可能看起来像这样:

def contains_conflicting_types(test, targets, conflicts):
    return not(all(t in targets for t in test) or all(t in conflicts for t in test))

如果把 targetsconflicts 变成集合(sets),那么这个操作会更快,因为在这种情况下,使用 in 这个操作符的速度是恒定的。如果你不能把输入变成集合,那么你可以这样写:

def contains_conflicting_types(test, targets, conflicts):
    targets, conflicts = set(targets), set(conflicts)
    return not(all(t in targets for t in test) or all(t in conflicts for t in test))

如果 test 也是一个集合,那么你可以利用重载的 <= 操作符来检查子集,代码可以写成:

def contains_conflicting_types(test, targets, conflicts):
    return not (test <= targets or test <= conflicts)
7

把所有东西都定义为集合(或者把它们转换成集合),这样就可以很简单地进行集合运算或者位运算了:

bool(oils & foo) ^ bool(waters & foo)
Out[19]: False

bool(oils & bar) ^ bool(waters & bar)
Out[20]: True

bool(oils & baz) ^ bool(waters & baz)
Out[21]: True

撰写回答