在较大列表中的一个列表中查找特定值序列

时间:2019-07-19 16:59:15

标签: python list

我试图以最有效的方式来确定List1=[0,0,0]包含在List2List3中,以及在哪里:

List2=[34, 32, 25, 0, 0, 0, 32]的结果为

List3=[34, 32, 25, 0, 32, 0, 0]的结果为 False

我尝试了set().subset,但返回了 True True ,我尝试了if List1 in List2并得到了 False < / p>

我知道我可以遍历列表并进行值,序列比较,但是想知道是否已经有一个函数可以进行这种比较,如果不能,可以使用一个相当简单的lambda表达式来完成?

注意:List2List3可能会更长一些,这些只是显示差异的简短示例,更确切地说是我要寻找的内容

5 个答案:

答案 0 :(得分:2)

我不知道为此设计的功能。但是,您可以使用lambda来实现。

is_contiguous_subsequence = lambda small, big: any(small == big[i:i+len(small)] for i in range(len(big) - len(small) + 1))

根据我的口味,lambda函数中包含的字符太多,因此建议将其设为常规函数。

def is_contiguous_subsequence(small, big):
    return any(small == big[i:i+len(small)] for i in range(len(big) - len(small) + 1))

根据any的性质,这将在找到第一个匹配项时返回True,而不继续进行big列表的其余部分。只是一点点效率奖励。

答案 1 :(得分:1)

正如一些评论所指出的那样,可读性和效率之间存在着张力。此解决方案提供较大列表中较小列表的索引,并且可以通过检查索引是否不是None来解决您的问题。

对于较小的父列表(长度为6),以下算法比更直接的解决方案快约2倍,而对于较长的列表(长度为10,000),以下算法可以快约15倍。

技巧是在每个项目上使用内置的list.index()函数来快速跳过父级列表。如果我们发现索引之间的任何大于1的间隔,我们都知道该序列已中断,但是无论它在哪里,我们都可以在此点附近开始。

def index_of(parent_list, sub_list):
    # No match possible
    if len(sub_list) > len(parent_list):
        return

    # Empty list 'matches' at index 0
    if not sub_list:
        return 0

    sequence_start = 0
    while True:
        try:
            match_found, offset = _sub_match(
                parent_list, sub_list, sequence_start)
        except ValueError:
            return

        if match_found:
            return sequence_start

        sequence_start = offset


def _sub_match(parent_list, sub_list, start_at):
    pos, last_offset = 0, start_at - 1
    # Skip through the items looking for the next index after the one before

    for item in sub_list:
        offset = parent_list.index(item, last_offset + 1)

        # We jumped more than one value, so the sequence is broken
        if offset - last_offset != 1:
            return False, offset - pos

        pos += 1
        last_offset = offset

    return True, last_offset

答案 2 :(得分:1)

首先感谢@brentertainer和@ jon-betts的见解。现在,我要重申的是,SubList是否仍包含在FullList中,因此我在@ jon-betts发布的内容中看到了效率的提高,但改为如下实现:

class ClassContainer:
    # This handles everything pertinent to this Class
    def __init__(self):
        self.ClassName = 'ThisClass'

    @staticmethod
    def IsSubSet(SubList, FullList):
        RetVal = False
        Item = SubList[0]
        Range = len(FullList) - len(SubList)
        LenAdjtr = len(SubList)

        for idx in range ( Range ):
            idx = FullList.index(Item, idx)
            if idx > Range:
                break
            if FullList[idx:(idx + LenAdjtr)] == SubList:
                RetVal = True
                break

        return RetVal

对于较长的序列,这无​​疑可以极大地简化该功能,该序列对于此应用程序非常有用,但它本身并不关心通过SubList进行挑剔,只是对其全部值进行了直接比较,这似乎更加有效。

答案 3 :(得分:0)

这是功能编程方式:

List1 = [0, 0, 0]

List2 = [34, 32, 25, 0, 0, 0]

f = lambda *args: True if \
    list(filter(lambda i: i in args[1] and \
    args[0].count(i) <= args[1].count(i), args[0])) == args[0] else False

print(f(List1, List2))
# True

答案 4 :(得分:0)

我喜欢这种方式,定义了一个返回生成器的方法:

def each_cons(ary, n = 2):
  if n < 2: n = 1
  i, size = 0, len(ary)
  while i < size-n+1:
    yield ary[i:i+n]
    i += 1

然后您可以像这样使用

list2= = [34, 32, 25, 0,  0, 0, 32]
chk = [0,0,0]

chk in each_cons(list2, len(chk))
#=> True


自我解释:

res = each_cons(list2, 3)
print(list(res))
#=> [[34, 32, 25], [32, 25, 0], [25, 0, 0], [0, 0, 0], [0, 0, 32]]