繁体   English   中英

如何检查列表中的所有项目是否都在另一个列表中?

[英]How to check if all items in a list are there in another list?

我有两个清单说

List1 = ['a','c','c']
List2 = ['x','b','a','x','c','y','c']

现在我想知道 List1 的所有元素是否都在 List2 中。 在这种情况下,都有。 我不能使用子集函数,因为我可以在列表中有重复的元素。 我可以使用 for 循环来计算 List1 中每个项目的出现次数,并查看它是否小于或等于 List2 中的出现次数。 有一个更好的方法吗?

谢谢。

当出现次数无关紧要时,您仍然可以通过动态创建集合来使用子集功能:

>>> list1 = ['a', 'c', 'c']
>>> list2 = ['x', 'b', 'a', 'x', 'c', 'y', 'c']
>>> set(list1).issubset(list2)
True

如果您需要检查每个元素在第二个列表中出现的次数是否至少与第一个列表中的相同,您可以使用 Counter 类型并定义您自己的子集关系:

>>> from collections import Counter
>>> def counterSubset(list1, list2):
        c1, c2 = Counter(list1), Counter(list2)
        for k, n in c1.items():
            if n > c2[k]:
                return False
        return True
   
>>> counterSubset(list1, list2)
True
>>> counterSubset(list1 + ['a'], list2)
False
>>> counterSubset(list1 + ['z'], list2)
False

如果您已经有计数器(无论如何这可能是存储数据的有用替代方案),您也可以将其写为一行:

>>> all(n <= c2[k] for k, n in c1.items())
True

请注意以下事项:

>>>listA = ['a', 'a', 'b','b','b','c']
>>>listB = ['b', 'a','a','b','c','d']
>>>all(item in listB for item in listA)
True

如果您像在英语中一样阅读“all”行,这并没有错,但可能会产生误导,因为 listA 有第三个 'b' 而 listB 没有。

这也有同样的问题:

def list1InList2(list1, list2):
    for item in list1:
        if item not in list2:
            return False
    return True

只是一个注释。 以下不起作用:

>>>tupA = (1,2,3,4,5,6,7,8,9)
>>>tupB = (1,2,3,4,5,6,6,7,8,9)
>>>set(tupA) < set(TupB)
False

如果将元组转换为列表,它仍然不起作用。 我不知道为什么字符串可以工作,但整数不行。

有效,但有相同的问题,即不记录元素出现次数:

>>>set(tupA).issubset(set(tupB))
True

使用集合不是多出现元素匹配的综合解决方案。

但这是一个单行解决方案/适应shantanoo的答案,无需尝试/除外:

all(True if sequenceA.count(item) <= sequenceB.count(item) else False for item in sequenceA)

使用三元条件运算符包装列表推导式的内置函数。 蟒蛇真棒! 请注意,“<=”不应为“==”。

使用此解决方案,序列 A 和 B 可以使用“计数”方法键入元组和列表以及其他“序列”。 两个序列中的元素都可以是大多数类型。 我不会像现在这样将它与 dicts 一起使用,因此使用“序列”而不是“可迭代”。

我不能使用子集函数,因为我可以在列表中有重复的元素。

这意味着您希望将列表视为multisets而不是sets 在 Python 中处理多集的常用方法是使用collections.Counter

Counter是用于计算可散列对象的 dict 子类。 它是一个无序集合,其中元素存储为字典键,它们的计数存储为字典值。 计数可以是任何整数值,包括零或负计数。 Counter类类似于其他语言中的 bag 或 multisets。

而且,虽然可以实现对多集的子集(与实施Counter的循环和比较计数,如)捅的答案,这是不必要的,就像你可以实现对集合的子集(与实施setfrozenset通过循环和测试) in ,但这是不必要的。

Counter类型已经实现了以明显的方式为多重集扩展的所有集合运算符。 <1因此,您可以根据这些运算符编写子集,并且开箱即Counter适用于setCounter

与(多)集差: 2

def is_subset(c1, c2):
    return not c1 - c2

或与(多)集合交集:

def is_subset(c1, c2):
    def c1 & c2 == c1

1. 你可能想知道为什么,如果Counter实现了集合运算符,它不只是为真子集和子集实现了<<= 虽然我找不到电子邮件线程,但我很确定已经讨论过这个问题,答案是“集合运算符”被定义为在collections.abc.Set的初始版本中定义的特定运算符collections.abc.Set (其中已经被扩大,IIRC ...),并非所有的运算符set恰好包括为了方便起见,在完全相同的方式, Counter没有名为类似的方法intersection这是友好的其他类型的比&只是因为set一样。

2. 这取决于这样一个事实,即 Python 中的集合在为空时预计为假,否则为真。 在此处针对内置类型进行了记录,并且在此处解释bool测试回退到len的事实-但这最终只是一个约定,因此如果有充分的理由,像 numpy 数组这样的“准集合”可能会违反它。 它适用于CounterOrderedDict等“真实集合”。如果您真的担心这一点,您可以编写len(c1 - c2) == 0 ,但请注意,这违背了PEP 8的精神。

如果 List1 中的所有项目都在 List2 中,这将返回 true

def list1InList2(list1, list2):
    for item in list1:
        if item not in list2:
            return False
    return True

使用Counter和内置交集方法的解决方案(请注意-是正确的多集差异,而不是逐元素减法):

from collections import Counter

def is_subset(l1, l2):
    c1, c2 = Counter(l1), Counter(l2)
    return not c1 - c2

测试:

>>> List1 = ['a','c','c']
>>> List2 = ['x','b','a','x','c','y','c']
>>> is_subset(List1, List2)
True
def check_subset(list1, list2):
    try:
        [list2.remove(x) for x in list1]
        return 'all elements in list1 are in list2'
    except:
        return 'some elements in list1 are not in list2'

暂无
暂无

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

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