简体   繁体   English

比较Python列表中的元素顺序

[英]Comparing element order in Python lists

I am trying to write a function that returns True if the elements in lst1 appear in lst2 in the same order as they appear in lst1 , but not necessarily consecutively. 我正在尝试编写一个函数,如果lst1的元素以与它们在lst1出现的顺序出现在lst2中,则返回True ,但不一定是连续的。

For example, 例如,

test([29, 5, 100], [20, 29, 30, 50, 5, 100]) should return True . test([29, 5, 100], [20, 29, 30, 50, 5, 100])应返回True

test([25, 65, 40], [40, 25, 30, 65, 1, 100]) should return False . test([25, 65, 40], [40, 25, 30, 65, 1, 100])应返回False

Here is what I have so far: 这是我到目前为止:

def test(lst1, lst2):
    for i in range(len(lst1)-len(lst2)+1):
        if lst2 == lst1[i:i+len(lst2)]:
            return True 
    return False 

Here is an iterative version of the method using index given by Triptych. 这是使用Triptych给出的index的方法的迭代版本。 I think this is probably the best way to do this, as index should be faster than any manual indexing or iteration: 我认为这可能是最好的方法,因为index应该比任何手动索引或迭代更快:

def test(lst1, lst2):
    start = 0
    try:
        for item in lst1:
            start = lst2.index(item, start) + 1
    except ValueError:
        return False
    return True

It should perform much better in Python than a recursive version. 它在Python中的表现要比递归版本好得多。 It also correctly adds one to the start point after each search so as not to give false positives when there are duplicates in the first list. 它还在每次搜索后正确地向起点添加一个,以便在第一个列表中存在重复时不给出误报。

Here are two solutions that iterate primarily over lst2 instead of lst1 , but are otherwise similar to jedwards' version. 这里有两个主要在lst2而不是lst1上迭代的解决方案,但在其他方面类似于jedwards的版本。

The first is straightforward, and uses indexing, but only indexes when you actually move to a different item in lst1 , rather than for every item in lst2 : 第一个是直截了当的,并使用索引,但只有当你实际移动到lst1的不同项而不是lst2每个项时索引:

def test(lst1, lst2):
    length, i, item = len(lst1), 0, lst1[0]
    for x in lst2:
        if x == item:
            i += 1
            if i == length:
                return True
            item = lst1[i]
    return False

The second uses manual iteration over lst1 with next rather than indexing: 第二种是使用手动遍历所有lst1next ,而不是索引:

def test(lst1, lst2):
    it = iter(lst1)
    try:
        i = next(it)
        for x in lst2:
            if x == i:
                i = next(it)
    except StopIteration:
        return True
    return False

Both are probably slight improvements as they do less indexing and have no need to construct a range for every item in lst1 . 两者都可能略有改进,因为它们的索引较少,并且不需要为lst1每个项构建range

Recursively, no clobbered lists, no new sublists, failing early 递归地,没有破坏列表,没有新的子列表,提前失败

def find_all(needle, haystack, npos=0, hpos=0):
  if npos >= len(needle):
    return True
  try:
    return find_all(needle, haystack, npos+1, haystack.index(needle[npos], hpos)+1) 
  except ValueError:
    return False


print find_all([1,3,5], [1,2,3,4,5,6,7]) # True
print find_all([1,5,3], [1,2,3,4,5,6,7]) # False

This scans the lists and is a different approach: 这会扫描列表,这是一种不同的方法:

def test(lst1, lst2):
    p2 = 0
    length = len(lst2)
    for e1 in lst1:
        for p in range(p2, length):
            if e1 == lst2[p]:
                p2 = p
                break
        else:
            return False    
    return True

For each element in lst1 it searches the subset of list 2 (between p2 and the end) for it. 对于lst1每个元素,它搜索列表2的子集(在p2和结束之间)。 If it is found, it restricts the range following searches by updating p2 . 如果找到,则通过更新p2限制搜索后的范围。 If it is not found, False is returned. 如果未找到,则返回False True is returned if every element in lst1 is found. 如果找到lst1每个元素,则返回True

def test(lst1, lst2):
    for x in lst2:
        if x == lst1[0]:
            del lst1[0]
    return lst1 == []

Should work. 应该管用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM