如何在不使用循环的情况下检查一个列表是否包含在另一个列表中?

26

有没有内置的方法可以检查一个列表是否包含在另一个列表中,而不需要进行任何循环?

我在 dir(list) 中查找了这个方法,但没有找到有用的东西。

5个回答

53

取决于您所说的“包含”的含义。 可能是这样:

if set(a) <= set(b):
    print("a is in b")

似乎与我的解决方案在功能上等效 - 有人知道哪个具有性能优势吗? - Etaoin
我不确定我能接受这个 -- sub 的调用是线性的,但 <= 不可能是免费的。我有什么遗漏吗? - Etaoin
7
set是哈希表,因此访问其中一个对象的成本为O(1)。在这段代码中,你需要遍历set(a)中的所有元素(O(len(set(a))))并检查该元素是否在set(b)中(O(1))。但是,总体成本当然不是(O(len(sublist))),因为必须先从列表构建集合。我不确定这个成本是多少,但我认为它应该是O(len(list)),因此总体成本为O(len(a)) + O(len(b)) + O(len(set(a))) - Felix Kling
好的!谢谢——我一直在缺乏对集合的常数时间访问。对你的评论和这个答案点赞。(当然,在我的最后一条评论中,subset的脑抽错误。) - Etaoin
如果 a = [1,1,2,3]b=[1,2,3]?你的代码认为 a 包含在 b 中,但实际上并不是这样。 - Adrien Plisson
@Adrien Plisson:这就是为什么我说“取决于你所说的‘包含’的具体意思”。 - nosklo

18

假设你想要确定sublist的所有元素是否也是superlist的元素:

all(x in superlist for x in sublist)

14

你可能希望使用一个set

if set(a).issubset(b):
    print('a is contained in b')

你的回答是否比nosklo的回答有任何优势? - xskxzr
1
是的,首先没有必要将两个'list'都转换为'set'。因此,我的建议可以节省一条指令(我已经使用'dis.dis()'进行了检查)。此外,由于方法'issubset'的冗长性,它更易读。 - jesteras

6
解决方案取决于您期望从列表中获得什么值。如果存在重复值的可能性,并且您需要检查测试容器中是否有足够的值,则以下解决方案效率较低:
def contained(candidate, container):
    temp = container[:]
    try:
        for v in candidate:
            temp.remove(v)
        return True
    except ValueError:
        return False

使用以下方式测试此功能:

>>> a = [1,1,2,3]
>>> b = [1,2,3,4,5]
>>> contained(a,b)
False    
>>> a = [1,2,3]
>>> contained(a,b)
True
>>> a = [1,1,2,4,4]
>>> b = [1,1,2,2,2,3,4,4,5]
>>> contained(a,b)
True

当然,这个解决方案可以大大改进:list.remove() 可能是耗时的,但可以通过巧妙的排序和索引来避免。但我不知道如何避免循环...(无论如何,任何其他解决方案都将使用集合或列表推导式来实现,这些都在内部使用循环...)

-1
如果您想验证列表1中的所有项目是否都在列表2中,可以使用以下列表推导式:
all(elem in list1 for elem in list2)

你也可以直接用返回该列表的代码替换list1和list2

all([snack in ["banana", "apple", "lemon", "chocolate", "chips"] for snack in ["chips","chocolate"])

任何 + 列表推导式都可以转换成这个形式,以更好地理解代码

return_value = False
for snack in snacks:
   if snack in groceries:
     return_value = True
   else:
     return_value = False

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接