简体   繁体   English

在Python中,如何检查项目列表是否是一个列表中的一个列表?

[英]In Python, how to you check to see if a list of items is exclusive to one list out of two?

I have two lists that contain mutually exclusive items - let's pick oil and water based liquids for these lists since these naturally can't mix: 我有两个包含互斥物品的清单 - 我们为这些清单选择油和水基液体,因为这些自然不能混合:

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

I want to test if foo only contains items in the water list or the oils list but NOT both. 我想测试foo是否只包含水列表或油类列表中的项目,但不包括两者。 such that: 这样:

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

my attempt so far: 到目前为止我的尝试:

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

needless to say it's ugly but works? 不用说它很难看但有效吗? how can I do it better? 我怎么能做得更好?

Define everything as sets (or convert them to sets) and then it's straightforward set/bitwise ops: 将所有内容定义为集合(或将它们转换为集合),然后是简单的set / bitwise操作:

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

A quick one-liner might look like: 快速单行可能看起来像:

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))

This would be faster if targets and conflicts were sets, since in that case the in operator would work in constant time. 如果设置targetsconflicts ,这将更快,因为在这种情况下in运算符将在恒定时间内工作。 If you can't make the inputs sets, then you can write: 如果你不能创建输入集,那么你可以写:

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))

If test is also a set, then you can take advantage of the overloaded <= operator that does subset checks and write: 如果test也是一个集合,那么你可以利用进行子集检查和写入的重载<=运算符:

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

Given the two sets to compare against 给出两组进行比较

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

And a test group 还有一个测试组

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

You can determine if the set contains items from exclusively one group (using the XOR operator) by checking if the sets are disjoint (two sets are disjoint if their intersection is the empty set). 您可以通过检查集合是否不相交来确定集合是否仅包含来自一个组的项目(使用XOR运算符)(如果它们的交集是空集,则两个集合是不相交的)。

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

For Python 2.5 and older, use: 对于Python 2.5及更早版本,请使用:

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

Alternatively, if you can remember that & is the intersection operator when acting on two sets. 或者,如果您能够记住&作为两组时的交叉算子。 Because readability counts, if you or other people who are (or will be) maintaining your code aren't sure what the & character means without looking it up, just use s1.intersection(s2) . 因为可读性很重要,如果您或其他人(或将要维护您的代码)不确定&字符意味着什么而不查找它,只需使用s1.intersection(s2)

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM