测试列表是否包含另一个Python列表

Non*_*one 43 python contains list list-comparison

如何测试列表是否包含另一个列表(即,它是一个连续的子序列).假设有一个名为contains的函数:

contains([1,2], [-1, 0, 1, 2]) # Returns [2, 3] (contains returns [start, end])
contains([1,3], [-1, 0, 1, 2]) # Returns False
contains([1, 2], [[1, 2], 3]) # Returns False
contains([[1, 2]], [[1, 2], 3]) # Returns [0, 0]
Run Code Online (Sandbox Code Playgroud)

编辑:

contains([2, 1], [-1, 0, 1, 2]) # Returns False
contains([-1, 1, 2], [-1, 0, 1, 2]) # Returns False
contains([0, 1, 2], [-1, 0, 1, 2]) # Returns [1, 3]
Run Code Online (Sandbox Code Playgroud)

Tho*_*s O 52

如果所有项目都是唯一的,则可以使用集合.

>>> items = set([-1, 0, 1, 2])
>>> set([1, 2]).issubset(items)
True
>>> set([1, 3]).issubset(items)
False
Run Code Online (Sandbox Code Playgroud)

  • 是的,特别是因为这是找到这个页面的一些人(比如我)的正确解决方案,他们不关心序列. (17认同)
  • 我认为最好显示一个想法是错误的(以便将来避免它),而不是完全删除它. (5认同)
  • 这不是op所期待的 (3认同)
  • 它仍然不起作用,即使所有项目都是唯一的,除非它们也按相同的顺序排列,没有混合的项目。例如,在“[1, 2, 3]”中找到“[1, 3]”或“[2, 1]”将给出误报。假设我们正在寻找序列本身,而不仅仅是序列中包含的值。 (3认同)
  • 查看者注意:本示例中提供的结果不准确。话虽如此,这个例子帮助了我。 (2认同)

Dav*_*rby 17

这是我的版本:

def contains(small, big):
    for i in xrange(len(big)-len(small)+1):
        for j in xrange(len(small)):
            if big[i+j] != small[j]:
                break
        else:
            return i, i+len(small)
    return False
Run Code Online (Sandbox Code Playgroud)

它返回一个(开始,结束+ 1)的元组,因为我认为这更像是pythonic,正如Andrew Jaffe在他的评论中指出的那样.它没有对任何子列表进行切片,因此应该合理有效.

对于新手感兴趣的一点是,它使用了else子句for语句 -这是不是我用的很频繁,但能在这样的情况是非常宝贵的.

这与在字符串中查找子字符串相同,因此对于大型列表,实现类似Boyer-Moore算法的方法可能更有效.

  • +1:不知道`for`的'else`条款!就在今天,我创建了一个笨拙的构造,涉及设置一个布尔值来完成这个. (2认同)

小智 16

有一个all()any()功能来做到这一点.检查list1是否包含list2中的所有元素

result = all(elem in list1 for elem in list2)
Run Code Online (Sandbox Code Playgroud)

检查list1是否包含list2中的任何元素

result = any(elem in list1 for elem in list2)
Run Code Online (Sandbox Code Playgroud)

变量result将是boolean(TRUE/FALSE).

  • 如果我没有弄错的话,`all(list1中的elem for list2中的elem)`正在针对list1中的项目测试list2中的所有项目,所以它是相反的。这会检查 list2 是否包含 list1 中的所有项目 (4认同)
  • 无论位置如何,“all(elem in big for elem insmall)”都会返回 true,这不是 OP 想要的。他们要求“连续的子序列”。 (3认同)

mar*_*eau 5

这有效并且相当快,因为​​它使用内置list.index()方法和==运算符进行线性搜索:

def contains(sub, pri):
    M, N = len(pri), len(sub)
    i, LAST = 0, M-N+1
    while True:
        try:
            found = pri.index(sub[0], i, LAST) # find first elem in sub
        except ValueError:
            return False
        if pri[found:found+N] == sub:
            return [found, found+N-1]
        else:
            i = found+1
Run Code Online (Sandbox Code Playgroud)


900*_*000 5

如果列表真的很大,我可以谦虚地建议Rabin-Karp 算法big。该链接甚至包含几乎可用的 Python 代码。


HIM*_*DEY 5

我总结并评估了不同技术所花费的时间

使用的方法有:

def containsUsingStr(sequence, element:list):
    return str(element)[1:-1] in str(sequence)[1:-1]


def containsUsingIndexing(sequence, element:list):
    lS, lE = len(sequence), len(element)
    for i in range(lS - lE + 1):
        for j in range(lE):
            if sequence[i+j] != element[j]: break
        else: return True
    return False


def containsUsingSlicing(sequence, element:list):
    lS, lE = len(sequence), len(element)
    for i in range(lS - lE + 1):
        if sequence[i : i+lE] == element: return True
    return False


def containsUsingAny(sequence:list, element:list):
    lE = len(element)
    return any(element == sequence[i:i+lE] for i in range(len(sequence)-lE+1))
Run Code Online (Sandbox Code Playgroud)

时间分析代码(平均超过 1000 次迭代):

from time import perf_counter

functions = (containsUsingStr, containsUsingIndexing, containsUsingSlicing, containsUsingAny)
fCount = len(functions)


for func in functions:
    print(str.ljust(f'Function : {func.__name__}', 32), end='   ::   Return Values: ')
    print(func([1,2,3,4,5,5], [3,4,5,5]) , end=', ')
    print(func([1,2,3,4,5,5], [1,3,4,5]))



avg_times = [0]*fCount
for _ in range(1000):
    perf_times = []
    for func in functions:
        startTime = perf_counter()
        func([1,2,3,4,5,5], [3,4,5,5])
        timeTaken = perf_counter()-startTime
        perf_times.append(timeTaken)
        

    for t in range(fCount): avg_times[t] += perf_times[t]

minTime = min(avg_times)
print("\n\n Ratio of Time of Executions : ", ' : '.join(map(lambda x: str(round(x/minTime, 4)), avg_times)))
Run Code Online (Sandbox Code Playgroud)

输出:

输出

结论:在这种情况下,切片操作被证明是最快的