检查Python中是否存在切片列表

时间:2010-07-22 21:19:15

标签: python list

我想编写一个函数来确定子列表是否存在于更大的列表中。

list1 = [1,0,1,1,1,0,0]
list2 = [1,0,1,0,1,0,1]

#Should return true
sublistExists(list1, [1,1,1])

#Should return false
sublistExists(list2, [1,1,1])

是否有可以执行此操作的Python函数?

12 个答案:

答案 0 :(得分:41)

让我们有点功能,好吗? :)

def contains_sublist(lst, sublst):
    n = len(sublst)
    return any((sublst == lst[i:i+n]) for i in xrange(len(lst)-n+1))

请注意any()将在lst内的第一个匹配项上停止 - 如果没有匹配则失败,在O(m * n)ops

之后

答案 1 :(得分:20)

如果您确定您的输入只包含单个数字0和1,那么您可以转换为字符串:

def sublistExists(list1, list2):
    return ''.join(map(str, list2)) in ''.join(map(str, list1))

这会创建两个字符串,因此它不是最有效的解决方案,但由于它利用了Python中优化的字符串搜索算法,它可能足以满足大多数目的。

如果效率非常重要,您可以查看适用于列表的Boyer-Moore字符串搜索算法。

天真的搜索有O(n * m)最坏的情况,但如果你不能使用转换为字符串技巧而且你不需要担心性能,那么它可能是合适的。

答案 2 :(得分:4)

我不知道

的功能
def sublistExists(list, sublist):
    for i in range(len(list)-len(sublist)+1):
        if sublist == list[i:i+len(sublist)]:
            return True #return position (i) if you wish
    return False #or -1

正如马克所说,这不是最有效的搜索(它是O(n * m))。可以通过与字符串搜索非常相似的方式处理此问题。

答案 3 :(得分:3)

有效的方法是使用Boyer-Moore algorithm,正如Mark Byers所说。我已在此处完成了此操作:Boyer-Moore search of a list for a sub-list in Python,但会在此处粘贴代码。它基于维基百科的文章。

search()函数返回要搜索的子列表的索引,或者失败时返回-1。

def search(haystack, needle):
    """
    Search list `haystack` for sublist `needle`.
    """
    if len(needle) == 0:
        return 0
    char_table = make_char_table(needle)
    offset_table = make_offset_table(needle)
    i = len(needle) - 1
    while i < len(haystack):
        j = len(needle) - 1
        while needle[j] == haystack[i]:
            if j == 0:
                return i
            i -= 1
            j -= 1
        i += max(offset_table[len(needle) - 1 - j], char_table.get(haystack[i]));
    return -1


def make_char_table(needle):
    """
    Makes the jump table based on the mismatched character information.
    """
    table = {}
    for i in range(len(needle) - 1):
        table[needle[i]] = len(needle) - 1 - i
    return table

def make_offset_table(needle):
    """
    Makes the jump table based on the scan offset in which mismatch occurs.
    """
    table = []
    last_prefix_position = len(needle)
    for i in reversed(range(len(needle))):
        if is_prefix(needle, i + 1):
            last_prefix_position = i + 1
        table.append(last_prefix_position - i + len(needle) - 1)
    for i in range(len(needle) - 1):
        slen = suffix_length(needle, i)
        table[slen] = len(needle) - 1 - i + slen
    return table

def is_prefix(needle, p):
    """
    Is needle[p:end] a prefix of needle?
    """
    j = 0
    for i in range(p, len(needle)):
        if needle[i] != needle[j]:
            return 0
        j += 1    
    return 1

def suffix_length(needle, p):
    """
    Returns the maximum length of the substring ending at p that is a suffix.
    """
    length = 0;
    j = len(needle) - 1
    for i in reversed(range(p + 1)):
        if needle[i] == needle[j]:
            length += 1
        else:
            break
        j -= 1
    return length

以下是问题中的示例:

def main():
    list1 = [1,0,1,1,1,0,0]
    list2 = [1,0,1,0,1,0,1]
    index = search(list1, [1, 1, 1])
    print(index)
    index = search(list2, [1, 1, 1])
    print(index)

if __name__ == '__main__':
    main()

输出:

2
-1

答案 4 :(得分:1)

这种方法适用于比Mark的

稍微脆弱的简单列表
def sublistExists(haystack, needle):
    def munge(s):
        return ", "+format(str(s)[1:-1])+","
    return munge(needle) in munge(haystack)

答案 5 :(得分:1)

def sublistExists(x, y):
  occ = [i for i, a in enumerate(x) if a == y[0]]
  for b in occ:
      if x[b:b+len(y)] == y:
           print 'YES-- SUBLIST at : ', b
           return True
      if len(occ)-1 ==  occ.index(b):
           print 'NO SUBLIST'
           return False

list1 = [1,0,1,1,1,0,0]
list2 = [1,0,1,0,1,0,1]

#should return True
sublistExists(list1, [1,1,1])

#Should return False
sublistExists(list2, [1,1,1])

答案 6 :(得分:0)

不妨投入@ NasBanov解决方案的递归版本

numpy <= 1.8.2

答案 7 :(得分:0)

def sublist(l1,l2):
  if len(l1) < len(l2):
    for i in range(0, len(l1)):
      for j in range(0, len(l2)):
        if l1[i]==l2[j] and j==i+1:
        pass
      return True
  else:
    return False

答案 8 :(得分:0)

以下是我最喜欢的简单解决方案(但是,它的野蛮作用,所以我不建议在大数据上使用它):

>>> l1 = ['z','a','b','c']
>>> l2 = ['a','b']
>>>any(l1[i:i+len(l2)] == l2 for i in range(len(l1)))
True

上面的代码实际上创建了所有长度为l2的l1切片,并​​将它们与l2进行顺序比较。

详细说明

仅当您不了解它的工作原理(并且想知道)时,才阅读此说明,否则无需阅读

首先,这是您可以遍历l1个项目的索引的方法:

>>> [i for i in range(len(l1))]
[0, 1, 2, 3]

因此,由于 i 表示l1中的项目索引,因此您可以使用它来显示该实际项目,而不是索引号:

>>> [l1[i] for i in range(len(l1))]
['z', 'a', 'b', 'c']

然后从l1创建长度为2的切片(类似于列表中项目的子选择):

>>> [l1[i:i+len(l2)] for i in range(len(l1))]
[['z', 'a'], ['a', 'b'], ['b', 'c'], ['c']] #last one is shorter, because there is no next item.

现在,您可以将每个切片与l2进行比较,然后看到第二个切片匹配:

>>> [l1[i:i+len(l2)] == l2 for i in range(len(l1))]
[False, True, False, False] #notice that the second one is that matching one

最后,使用名为 any 的函数,您可以检查至少一个布尔值是否为True:

>>> any(l1[i:i+len(l2)] == l2 for i in range(len(l1)))
True

答案 9 :(得分:0)

我知道这可能与原始问题不太相关,但如果两个列表中的项目顺序无关紧要,那么对于其他人来说,这可能是非常优雅的 1 行解决方案。如果 List1 元素在 List2 中(无论顺序如何),下面的结果将显示 True。如果订单很重要,则不要使用此解决方案。

List1 = [10, 20, 30]
List2 = [10, 20, 30, 40]
result = set(List1).intersection(set(List2)) == set(List1)
print(result)

输出

True

答案 10 :(得分:-3)

如果我正确理解这一点,你有一个更大的列表,如:

list_A= ['john', 'jeff', 'dave', 'shane', 'tim']

然后还有其他列表

list_B= ['sean', 'bill', 'james']

list_C= ['cole', 'wayne', 'jake', 'moose']

然后我将列表B和C附加到列表A

list_A.append(list_B)

list_A.append(list_C)

所以当我打印list_A

print (list_A)

我得到以下输出

['john', 'jeff', 'dave', 'shane', 'tim', ['sean', 'bill', 'james'], ['cole', 'wayne', 'jake', 'moose']]

现在我想检查子列表是否存在:

for value in list_A:
    value= type(value)
    value= str(value).strip('<>').split()[1]
    if (value == "'list'"):
        print "True"
    else:
        print "False"
如果你在较大的列表中有任何子列表,这将给你'真'。

答案 11 :(得分:-3)

只需从两个列表中创建集合并使用issubset函数:

def sublistExists(big_list, small_list):
    return set(small_list).issubset(set(big_list))