首页 > 解决方案 > 有效地循环遍历一对列表来比较元素

问题描述

我有 2 个清单。其中之一是列表列表。进一步来说:

lst1 = [[4, 5, 6], [19, 20, 24, 25]]
lst2 = [8, 21]

每个列表列表的数字代表索引

我想要做的是删除lst2 不在每个列表的索引之间的任何元素lst1

例如,数字8 fromlst2应该被删除,因为它不在 的两个列表(元素)的第一个和最后一个数字之间lst1。不应删除数字 21,因为它位于 的第二个列表(元素)的第一个和最后一个元素之间lst2

到目前为止我写的代码是:

for elem2 in lst2:
    count = 0
    for elem1 in lst1:
        minsubelem = min(elem1)
        maxsubelem = max(elem1)
                
        condition = not ((elem2 > minsubelem) and (elem2 < maxsubelem))
        
        if condition:
            count += 1
            
    if count == len(lst1):
        index = lst2.index(elem2)
        lst2.pop(index)

print(lst2)

返回:

[21]

这可行,但正如您可以想象的那样,使用 2 个 for 循环并不是最优的,如果列表很长,计算时间可能会显着增加。

为了提高效率,该代码的潜在替代品应该是什么?

说明:

  1. 中的索引lst2 永远不等于中的任何索引 lst1
  2. 我已经阅读了itertools文档,但可能我缺乏将建议的方法链接到我的用例的经验。

标签: pythonlist

解决方案


如果您保证对其中的子列表lst1进行排序,则无需查找每个子列表的最小值和最大值。只需抓住每个子列表的第一个和最后一个元素,并将它们用作您的最小值和最大值。此外,一般来说,保留所需元素而不是清除不想要的元素要容易和干净得多 - 而不是弹出你不想要的元素,只需构建一个新列表,只保留你想要的那些元素:

lst1 = [[4, 5, 6], [19, 20, 24, 25]]
lst2 = [8, 21]

def predicate(value):
    return any(l[0] < value < l[-1] for l in lst1)

print(list(filter(predicate, lst2)))

输出:

[21]
>>> 

编辑 - 为了解决您无法使用的问题filter(因为您需要将您的lst1作为参数传递给predicate),您可以使用functools.partial

from functools import partial

lst1 = [[4, 5, 6], [19, 20, 24, 25]]
lst2 = [8, 21]

def predicate(value, ranges):
    return any(l[0] < value < l[-1] for l in ranges)

print(list(filter(partial(predicate, ranges=lst1), lst2)))

注意,最后这仍然基本上等同于使用两个循环。一个“循环”遍历 中的所有项目lst2,对每个项目调用谓词,另一个循环遍历lst1(调用rangesin predicate)中的每个子列表。不过,由于发生在any.


推荐阅读