Python 检查列表是否是子列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35964155/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 17:12:32  来源:igfitidea点击:

Checking if list is a sublist

python

提问by MMM

I need to check if list1 is a sublist of list2 (True; if every integer in list2 that is common with list1 is in the same order of indexes as in list1)

我需要检查 list1 是否是 list2 的子列表(真;如果 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

Can anybody help me... why isn't this working?

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

采纳答案by L3viathan

i need to check if list1 is a sublist to list2 (True; if every integer in list2 that is common with list1 is in the same order of indexes as in list1)

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

Your code isn't working because as soon as a list element in ls1 doesn't occur in ls2 it will return False immediately.

您的代码不起作用,因为只要 ls1 中的列表元素没有出现在 ls2 中,它就会立即返回 False 。

This creates two lists that contain only the common elements (but in their original order) and then returns True when they are the same:

这将创建两个仅包含公共元素(但按其原始顺序)的列表,然后在它们相同时返回 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

edit:A memory-efficient variant:

编辑:内存高效的变体:

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

回答by Goodies

Another way that we do this is with collections.Counter. @L3viathan's second answer is the most efficient and fastest way to do it.

我们这样做的另一种方法是使用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

His 2nd way is faster by an order of magnitude, but I wanted to mention the Counter variant because of its prevalence and usage outside of this scenario.

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

回答by Ar?imede? ?ontegasppα ?acilhα?

An easy way to check if all elements of a list are in other one is converting both to sets:

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

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

回答by Geislor Crestani

Another easy way is to use list comprehensionAnd use the built-in function allto verify that all items in list1 are contained in list2.

另一种简单的方法是使用列表推导并使用内置函数all来验证 list1 中的所有项都包含在 list2 中。

Example:

例子:

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

all(i in list2 for i in list1)

回答by Dave Thomas

Memory efficient solution based on M. Morgan's answer. Takes into consideration that in order to be a sublist, the sublist must be found in the same order in the super list.

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

Variable kkeeps track of the length of matched characters. When this matches the length of our sublist we can return true.

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

Variable skeeps track of the starting value. I keep track of this so that a test case like sublist(["1", "1", "2"],["0", "1", "1", "1", "2", "1", "2"])with extraneous repeats of the first entry don't affect the current index reset when unmatched. Once the starting value changes sbecomes irrelevant so this case does not fire in the middle of a pattern.

变量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

回答by codename47

b = sublistand a = listthen search b by splitting a in lengths of b

b = sublista = list然后通过分割一在长度搜索家庭b

e.g.

例如

>>> a = [2,4,3,5,7] , b = [4,3]
>>> b in [a[i:len(b)+i] for i in xrange(len(a))]
True

>>> a = [2,4,3,5,7] , b = [4,10]
>>> b in [a[i:len(b)+i] for i in xrange(len(a))]

False

回答by Umair Bhatti

Its easy with iterators.

使用迭代器很容易。

>>> 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

回答by Sanjana Mantri

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

回答by M. Morgan

I found the above all found ['a','b','d'] to be a sublist of ['a','b','c','e','d'], which may not be true in spite of all of the elements of the sublist being present in the list. So to maintain the order and I came up with:

我发现以上所有发现 ['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

Whilst this isn't very memory efficient, I find it works quite well with small lists.

虽然这不是很有效的内存,但我发现它在小列表中工作得很好。

回答by gilch

def has_ordered_intersection(xs, ys):
    common = {*xs} & {*ys}
    return all(x == y for x, y in zip((x for x in xs if x in common),
                                      (y for y in ys if y in common)))

This passes @L3viathan's doctest with fewer lines of code, using a similar strategy to the "memory-efficient variant", and with arguably greater overall efficiency.

这通过了@L3viathan 的 doctest,代码行更少,使用类似于“内存高效变体”的策略,并且可以说整体效率更高。

>>> has_ordered_intersection([], [1,2,3])
True
>>> has_ordered_intersection([1,2,3,4], [2,5,3])
True
>>> has_ordered_intersection([1,2,3,4], [0,3,2])
False
>>> has_ordered_intersection([1,2,3,4], [1,2,5,6,7,8,5,76,4,3])
False

I used the intersection set instead of a generator because I think the extra memory is a good tradeoff compared to the time cost of shortcut-scanning the entire list per element (what indoes to a list), especially if they are long.

我使用了交集而不是生成器,因为我认为与快捷扫描每个元素的整个列表的时间成本相比,额外的内存是一个很好的权衡(对in列表有什么影响),尤其是当它们很长时。

I also don't think this should be called a "sublist" since xsis allowed to have elements that ysdoes not. The above relation is symmetric: swapping the arguments doesn't change the answer. A real ordered "sublist" would not be symmetric and look more like this

我也不认为这应该被称为“子列表”,因为xs允许具有ys不包含的元素。上述关系是对称的:交换参数不会改变答案。真正有序的“子列表”不会是对称的,看起来更像这样

def is_ordered_sublist(xs, ys):
    xset = {*xs}
    return all(x == y for x, y in zip(xs, (y for y in ys if y in xset)))