问题 检查列表是否是子列表


我需要检查list1是否是list2的子列表(True;如果list2中与list1相同的每个整数与list1中的索引顺序相同)

def sublist(lst1,lst2):
    for i in range(len(lst1)):
        if lst1[i] not in lst2:
            return False
        for j in range(len(lst2)):
            if (lst1[j] in lst2) and (lst2.index(lst1[i+1]) > lst2.index(lst1[i])):
                return True

任何人都可以帮助我......为什么这不起作用?


13085
2018-03-12 22:35


起源

你能举例说明这应该返回True和False吗? - L3viathan
嗯,一个人,你回来了 True 在第二次循环中的第一次击中时,你可能想要返回 False 在第一个mishit,和 True 当循环结束时。 - schwobaseggl
列表1中的重复项必须在list2中多次出现? - schwobaseggl


答案:


我需要检查list1是否是list2的子列表(True;如果list2中与list1相同的每个整数与list1中的索引顺序相同)

您的代码无法正常工作,因为只要ls1中的列表元素未在ls2中出现,它就会立即返回False。

这将创建两个仅包含公共元素的列表(但按原始顺序排列),然后在它们相同时返回True:

def sublist(lst1, lst2):
   ls1 = [element for element in lst1 if element in lst2]
   ls2 = [element for element in lst2 if element in lst1]
   return ls1 == ls2

编辑: 一种节省内存的变体:

def sublist(ls1, ls2):
    '''
    >>> sublist([], [1,2,3])
    True
    >>> sublist([1,2,3,4], [2,5,3])
    True
    >>> sublist([1,2,3,4], [0,3,2])
    False
    >>> sublist([1,2,3,4], [1,2,5,6,7,8,5,76,4,3])
    False
    '''
    def get_all_in(one, another):
        for element in one:
            if element in another:
                yield element

    for x1, x2 in zip(get_all_in(ls1, ls2), get_all_in(ls2, ls1)):
        if x1 != x2:
            return False

    return True

4
2018-03-12 22:37



内存效率低下,特别是大型列表,但至少它考虑到每个的数量:) - Goodies
@Goodies添加了内存效率版本:P - L3viathan
中的变量 get_all_in 功能应该是 lst1和 lst2,但这只是一个错字。我喜欢!添加补充答案。 - Goodies
@Goodies我没有看到错字。 - L3viathan
也许这是我的坏事。您更改了参数 lst1 至 ls1 分别在第一和第二。道歉。 - Goodies


我们这样做的另一种方式是 collections.Counter。 @L3viathan的第二个答案是最有效和最快速的方法。

def sublist1(lst1, lst2):
    ls1 = [element for element in lst1 if element in lst2]
    ls2 = [element for element in lst2 if element in lst1]
    return ls1 == ls2


def sublist2(lst1, lst2):
    def get_all_in(one, another):
        for element in one:
            if element in another:
                yield element
    for x1, x2 in zip(get_all_in(lst1, lst2), get_all_in(lst2, lst1)):
        if x1 != x2:
            return False
    return True


def sublist3(lst1, lst2):
    from collections import Counter
    c1 = Counter(lst1)
    c2 = Counter(lst2)
    for item, count in c1.items():
        if count > c2[item]:
            return False
    return True


l1 = ["a", "b", "c", "c", "c", "d", "e"]
l2 = ["c", "a", "c", "b", "c", "c", "d", "d", "f", "e"]

s1 = lambda: sublist1(l1, l2)
s2 = lambda: sublist2(l1, l2)
s3 = lambda: sublist3(l1, l2)

from timeit import Timer
t1, t2, t3 = Timer(s1), Timer(s2), Timer(s3)
print(t1.timeit(number=10000))  # => 0.034193423241588035
print(t2.timeit(number=10000))  # => 0.012621842119714115
print(t3.timeit(number=10000))  # => 0.12714286673722477

他的第二种方式更快一个数量级,但我想提到Counter变体,因为它在这种情况之外的流行和使用。


2
2018-03-13 01:17





基于M. Morgan答案的内存有效解决方案。考虑到为了成为子列表,必须在超级列表中以相同的顺序找到子列表。

变量 k 跟踪匹配字符的长度。当这与我们的子列表的长度匹配时,我们可以返回true。

变量 s 跟踪起始值。我跟踪这个,以便测试用例 sublist(["1", "1", "2"],["0", "1", "1", "1", "2", "1", "2"]) 与第一个条目的无关重复不会影响当前不匹配的索引重置。一旦起始值发生变化 s 变得无关紧要,所以这种情况不会在模式中间触发。

def sublist(sublist, lst):
    if not isinstance(sublist, list):
        raise ValueError("sublist must be a list")
    if not isinstance(lst, list):
        raise ValueError("lst must be a list")

    sublist_len = len(sublist)
    k=0
    s=None

    if (sublist_len > len(lst)):
        return False
    elif (sublist_len == 0):
        return True

    for x in lst:
        if x == sublist[k]:
            if (k == 0): s = x
            elif (x != s): s = None
            k += 1
            if k == sublist_len:
                return True
        elif k > 0 and sublist[k-1] != s:
            k = 0

    return False

2
2018-01-19 17:06





检查列表的所有元素是否在另一个元素中的简单方法是将两者都转换为集合:

def sublist(lst1, lst2):
    return set(lst1) <= set(lst2)

1
2018-03-13 02:40



没错,但这并不能回答原来的问题。您还需要检查元素是否以相同的顺序出现 - 并且使用集合将无助于此。 - Bogd
这是真的,你是对的。 - Arĥimedeς ℳontegasppα ℭacilhας


我发现以上都发现['a','b','d']是['a','b','c','e','d']的子列表,可能不是尽管子列表中的所有元素都存在于列表中,但仍为true。所以为了维持秩序,我想出了:

def sublist4(sublist,lst):
    #Define an temp array to populate 
    sub_list=[]
    comparable_sublist=[]
    #Define two constants to iterate in the while loop
    i=0
    k=0
    #Loop the length of lst
    while i < len(lst):
        #If the element is in the sublist append to temp array, 
        if k < len(sublist) and lst[i] == sublist[k]:
            sub_list.append(lst[i])
            #set a comparable array to the value of temp array
            comparable_sublist = sub_list
            k += 1
            #If the comparable array is the same as the sublist, break
            if len(comparable_sublist) == len(sublist):
                break

        #If the element is not in the sublist, reset temp array
        else:
            sub_list = []


        i += 1

    return comparable_sublist == sublist

虽然这不是非常有效的内存,但我发现它适用于小型列表。


1
2018-01-05 09:06



您还需要考虑重置变量 k。 sublist4([1,2,4],[1,2,7,4,1,2,4]) 失败。考虑到订单,您走在正确的轨道上。在查看原始问题时,提问者确实提到子列表必须按顺序排列。 - Dave Thomas


它很容易用迭代器。

>>> a = [0,1,2]
>>> b = [item for item in range(10)]
>>> b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a
[0, 1, 2]
>>> [False, True][set([item in b for item in a]) == set([True])]
True
>>> a = [11, 12, 13]
>>> [False, True][set([item in b for item in a]) == set([True])]
False

1
2018-02-28 10:18



set([item in b for item in a]) => {item in b for item in a} (更高效) - Jean-François Fabre


另一个简单的方法是使用 列表理解 并使用内置功能 所有 验证list1中的所有项都包含在list2中。

例:

list1 = ['1','2']
list2 = ['1','2',3]

all(i in list2 for i in list1)

0
2018-05-19 17:06



从审核队列: 我可以请求您在答案中添加更多背景信息。仅代码的答案很难理解。如果您可以在帖子中添加更多信息,它将帮助提问者和未来的读者。 - help-info.de
这很简洁,但不考虑订单 - Davi Lima


def sublist(l1,l2):
    s1=" ".join(str(i) for i in l1)
    s2=" ".join(str(i) for i in l2)
    if s1 in s2:
        return True
    else:
        return False

0
2017-09-25 05:59



要回答这个问题,您不能假设列表能够转换为字符串。如果是这种情况,您可以使用 l1 in l2 直。 - TimZaman


试试这个!!子列表y没有缺少列表x的序列。

x =列表

y =子列表

if ([i for i,j in enumerate(y) for k,l in enumerate(x) if i == k and j!=l]):
    print("True")
else:
    print("False")

0
2018-06-25 05:34