Python - 验证一个列表是否是另一个列表的子集

时间:2013-05-16 04:37:03

标签: python list

我需要验证列表是否是另一个列表的一个子集 - 布尔返回是我所寻求的全部 在交叉路口之后,在最小的列表上测试相等性是最快的方法吗? 鉴于需要比较的数据集数量,性能至关重要 根据讨论添加更多事实:

  1. 对于许多测试,其中一个列表是否相同?
    它确实是其中一个是静态查找表
  2. 是否需要成为清单?
    它没有 - 静态查找表可以是表现最佳的任何东西 动态的是一个dict,我们从中提取密钥以执行静态查找。
  3. 根据情景,最佳解决方案是什么?

17 个答案:

答案 0 :(得分:101)

Python为此提供的高性能函数是set.issubset。但它确实有一些限制,不清楚它是否是你问题的答案。

列表可能包含多次项目并具有特定订单。一套没有。要实现高性能集,只能处理hashable个对象。

您是在询问子集还是子序列(这意味着您需要字符串搜索算法)?对于许多测试,其中一个列表是否相同?列表中包含哪些数据类型?就此而言,它是否需要成为一个清单?

您的其他帖子intersect a dict and list使类型更清晰,并建议使用字典键视图来实现类似集合的功能。在那种情况下,它是有用的,因为字典键的行为就像一个集合(以至于在我们使用Python之前我们使用字典之前)。人们想知道这个问题在三小时内如何变得不那么具体。

答案 1 :(得分:101)

>>> a = [1, 3, 5]
>>> b = [1, 3, 5, 8]
>>> c = [3, 5, 9]
>>> set(a) <= set(b)
True
>>> set(c) <= set(b)
False

>>> a = ['yes', 'no', 'hmm']
>>> b = ['yes', 'no', 'hmm', 'well']
>>> c = ['sorry', 'no', 'hmm']
>>> 
>>> set(a) <= set(b)
True
>>> set(c) <= set(b)
False

答案 2 :(得分:30)

do the decoding, rendering and encoding in the same thread

说明:生成器通过循环遍历列表one = [1, 2, 3] two = [9, 8, 5, 3, 2, 1] all(x in two for x in one) 来检查该项是否在列表one中来创建布尔值。 Show + capture camera如果每个项目都是真实的,则返回two,否则True

还有一个优点是False在缺少元素的第一个实例上返回False,而不是必须处理每个项目。

答案 3 :(得分:20)

假设物品是可以清洗的

>>> from collections import Counter
>>> not Counter([1, 2]) - Counter([1])
False
>>> not Counter([1, 2]) - Counter([1, 2])
True
>>> not Counter([1, 2, 2]) - Counter([1, 2])
False

如果你不关心重复的项目,例如。 [1, 2, 2][1, 2]然后只需使用:

>>> set([1, 2, 2]).issubset([1, 2])
True
  

在交叉路口之后,在最小的列表上测试相等性是最快的方法吗?

.issubset将是最快的方式。在测试issubset之前检查长度不会提高速度,因为您仍然需要迭代并检查O(N + M)个项目。

答案 4 :(得分:5)

另一个解决方案是使用intersection

one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]

set(one).intersection(set(two)) == set(one)

集合的交集将包含set one

(OR)

one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]

set(one) & (set(two)) == set(one)

答案 5 :(得分:3)

我知道它已经很晚了,但只是想用适合我的方式更新答案 (Python 3)

# var 1
x = [1,2,3,4]
#  var 2
y = [1,2]

# check if var2 is subset of var1
all([z in x for z in y])

干杯。

答案 6 :(得分:1)

由于没有人考虑过比较两个字符串,所以这是我的建议。

您当然想检查管道(“ |”)是否不在两个列表中,并可能自动选择另一个字符,但是您明白了。

使用空字符串作为分隔符不是解决方案,因为数字可以有几个数字([12,3]!= [1,23])

def issublist(l1,l2):
    return '|'.join([str(i) for i in l1]) in '|'.join([str(i) for i in l2])

答案 7 :(得分:1)

集合理论不适合列表,因为重复使用集合理论会导致错误的答案。

例如:

SELECT  p.Id ,
            p.Name ,
            p.ShortDescription ,
            p.DisplayOrder ,
            cat.Name AS CategoryName
    FROM    dbo.Product AS p
            CROSS APPLY (
                SELECT TOP 1
                    c.Name ,
                    c.Description ,
                    c.Id,
                    (CASE WHEN CONTAINS(cat.NAME, @search) THEN 1 ELSE 0 END) as IsCategoryMatching
                FROM      dbo.Product_Category_Mapping AS m
                LEFT JOIN dbo.Category AS c ON m.CategoryId = c.Id
                WHERE m.ProductId = p.Id
                      AND c.Published = 1
                      AND c.Deleted = 0
            ) AS cat    
    WHERE   p.Published = 1
            AND p.Deleted = 0
            AND ( CONTAINS ( p.NAME, @search )
                  OR CONTAINS ( p.FullDescription, @search )
                  OR cat.IsCategoryMatching=1
                );

没有意义。是的,它给出了错误的答案,但这是不正确的,因为集合论只是比较:1,3,5对1,3,4,5。您必须包含所有重复项。

相反,您必须计算每个项目的每个匹配项并执行大于等于检查的值。这不是很昂贵,因为它不使用O(N ^ 2)操作,也不需要快速排序。

a = [1, 3, 3, 3, 5]
b = [1, 3, 3, 4, 5]
set(b) > set(a)

然后运行这个你得到:

#!/usr/bin/env python

from collections import Counter

def containedInFirst(a, b):
  a_count = Counter(a)
  b_count = Counter(b)
  for key in b_count:
    if a_count.has_key(key) == False:
      return False
    if b_count[key] > a_count[key]:
      return False
  return True


a = [1, 3, 3, 3, 5]
b = [1, 3, 3, 4, 5]
print "b in a: ", containedInFirst(a, b)

a = [1, 3, 3, 3, 4, 4, 5]
b = [1, 3, 3, 4, 5]
print "b in a: ", containedInFirst(a, b)

答案 8 :(得分:1)

one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]

set(x in two for x in one) == set([True])

如果list1在列表2中:

  • (x in two for x in one)生成True列表。

  • 当我们执行set(x in two for x in one)时只有一个元素(True)。

答案 9 :(得分:1)

尝试按位AND

>>> set([1,2]) & set([1,2,3])
set([1, 2])
>>> set([0]) & set([1,2,3])
set([])

尚未对其进行分析。

答案 10 :(得分:0)

下面的代码检查给定的集合是否是另一个集合的“适当子集”

 def is_proper_subset(set, superset):
     return all(x in superset for x in set) and len(set)<len(superset)

答案 11 :(得分:0)

如果我迟到了,请原谅我。 ;)

要检查一个set Aset B的子集,PythonA.issubset(B)还是A <= B。它仅适用于set并且效果很好内部实现的复杂性未知。参考:https://docs.python.org/2/library/sets.html#set-objects

我想出了一个算法来检查list A是否是list B的子集,并附有以下备注。

  • 为了降低查找子集的复杂性,我觉得它很合适 在比较要符合条件的元素之前,sort首先列出 子集。
  • 当第二个列表break的元素值大于第一个列表loop的元素值时,它帮助我B[j] A[i]
  • last_index_j用于启动loop超过list B的位置。它有助于避免从一开始就开始比较 list B(正如您可能认为不必要的那样,在后续list B中从index 0开始iterations。)
  • 复杂性将O(n ln n)用于对两个列表进行排序,O(n)用于检查子集。
    O(n ln n) + O(n ln n) + O(n) = O(n ln n)

  • 代码包含大量print个语句,可以查看iteration的每个loop发生了什么。这些是为了理解 仅

检查一个列表是否是另一个列表的子集

is_subset = True;

A = [9, 3, 11, 1, 7, 2];
B = [11, 4, 6, 2, 15, 1, 9, 8, 5, 3];

print(A, B);

# skip checking if list A has elements more than list B
if len(A) > len(B):
    is_subset = False;
else:
    # complexity of sorting using quicksort or merge sort: O(n ln n)
    # use best sorting algorithm available to minimize complexity
    A.sort();
    B.sort();

    print(A, B);

    # complexity: O(n^2)
    # for a in A:
    #   if a not in B:
    #       is_subset = False;
    #       break;

    # complexity: O(n)
    is_found = False;
    last_index_j = 0;

    for i in range(len(A)):
        for j in range(last_index_j, len(B)):
            is_found = False;

            print("i=" + str(i) + ", j=" + str(j) + ", " + str(A[i]) + "==" + str(B[j]) + "?");

            if B[j] <= A[i]:
                if A[i] == B[j]:
                    is_found = True;
                last_index_j = j;
            else:
                is_found = False;
                break;

            if is_found:
                print("Found: " + str(A[i]));
                last_index_j = last_index_j + 1;
                break;
            else:
                print("Not found: " + str(A[i]));

        if is_found == False:
            is_subset = False;
            break;

print("subset") if is_subset else print("not subset");

<强>输出

[9, 3, 11, 1, 7, 2] [11, 4, 6, 2, 15, 1, 9, 8, 5, 3]
[1, 2, 3, 7, 9, 11] [1, 2, 3, 4, 5, 6, 8, 9, 11, 15]
i=0, j=0, 1==1?
Found: 1
i=1, j=1, 2==1?
Not found: 2
i=1, j=2, 2==2?
Found: 2
i=2, j=3, 3==3?
Found: 3
i=3, j=4, 7==4?
Not found: 7
i=3, j=5, 7==5?
Not found: 7
i=3, j=6, 7==6?
Not found: 7
i=3, j=7, 7==8?
not subset

答案 12 :(得分:0)

在python 3.5中,您可以执行[*set()][index]来获取元素。它比其他方法慢得多。

one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]

result = set(x in two for x in one)

[*result][0] == True

或只使用len和set

len(set(a+b)) == len(set(a))

答案 13 :(得分:0)

在这里,我知道一个列表是否是另一个列表的子集,这对我而言很重要。

def is_subset(list_long,list_short):
    short_length = len(list_short)
    subset_list = []
    for i in range(len(list_long)-short_length+1):
        subset_list.append(list_long[i:i+short_length])
    if list_short in subset_list:
        return True
    else: return False

答案 14 :(得分:0)

大多数解决方案都认为列表没有重复项。如果您的列表确实有重复,可以尝试以下操作:

def isSubList(subList,mlist):
    uniqueElements=set(subList)
    for e in uniqueElements:
        if subList.count(e) > mlist.count(e):
            return False     
    # It is sublist
    return True

这可以确保子列表中的元素绝不会与列表中的元素不同,也不会包含更多的公共元素。

lst=[1,2,2,3,4]
sl1=[2,2,3]
sl2=[2,2,2]
sl3=[2,5]

print(isSubList(sl1,lst)) # True
print(isSubList(sl2,lst)) # False
print(isSubList(sl3,lst)) # False

答案 15 :(得分:-1)

如果您询问一个列表是否“包含”在另一个列表中,则:

>>>if listA in listB: return True

如果您询问listA中的每个元素是否在listB中具有相同数量的匹配元素,请尝试:

all(True if listA.count(item) <= listB.count(item) else False for item in listA)

答案 16 :(得分:-2)

如果a2 is subset of a1,则Length of set(a1 + a2) == Length of set(a1)

a1 = [1, 2, 3, 4, 5];
a2 = [1, 2, 3];

len(set(a1)) == len(set(a1 + a2))