Python 有没有更快的方法从一个列表中搜索另一个列表中的项目?

Python 有没有更快的方法从一个列表中搜索另一个列表中的项目?,python,list,Python,List,我有两个文件名列表。第二个列表中的名称包含第一个列表中的名称,例如: lst1 = ['file1', 'file2', 'file3'] lst2 = ['file2_processed', 'file1_processed', 'file3_processed'] lst3 = [['file1', 'file1_processed'], ['file2', 'file2_processed'], ['file3', 'file3_processed']]

我有两个文件名列表。第二个列表中的名称包含第一个列表中的名称,例如:

lst1 = ['file1', 'file2', 'file3']
lst2 = ['file2_processed', 'file1_processed', 'file3_processed']
lst3 = [['file1', 'file1_processed'],
        ['file2', 'file2_processed'],
        ['file3', 'file3_processed']]
lst2
中的文件名顺序与
lst1
中的文件名顺序不同,这就是问题所在

我需要获得一个包含成对
lst1
条目和相应
lst2
条目的列表,例如:

lst1 = ['file1', 'file2', 'file3']
lst2 = ['file2_processed', 'file1_processed', 'file3_processed']
lst3 = [['file1', 'file1_processed'],
        ['file2', 'file2_processed'],
        ['file3', 'file3_processed']]
我想到的就是这个函数:

def pairs(a, b):
    c = []
    for wa in a:
        for wb in b:
            if wa in wb:
                c.append([wa, wb])
    return c

但是这个在庞大的列表上速度非常慢,所以我想问:有没有更快的方法来执行这个操作?

如果您关心创建
O(n^2)
列表,那么我建议您使用
itertools
模块中的迭代器:

import itertools as it

def parse(haystack, needle):
    return (x for x in it.product(haystack, needle) where x[1] in x[0])
另一种可能的优化:如果模式总是在
中查找
,则不使用
in
操作符,您可能希望调用
str.startwiths
方法:

return (x for x in it.product(haystack, needle) where x[0].startswith(x[1]))
当然,
.txt
会妨碍


订单有意义吗?如果没有,您可能希望对这两个列表进行排序,只搜索干草堆中相关的部分。

最好的方法可能是使用列表理解将其全部导入,否则就完全按照您所做的操作进行。如果比较两个排序列表,没有比O(n^2)更快的算法。请注意,如果您必须进行多个排序,则排序
lst2
和使用
itertools.groupby
按前缀分组几乎总是更快

lst1 = ['file1.txt', 'file2.txt', 'file3.txt']
lst2 = ['file2_processed.txt', 'file1_processed.txt', 'file3_processed.txt']

lst3 = [(prefix, [fullname for fullname in lst2 if fullname.startswith(prefix)]) for
        prefix in lst1]
正如我前面提到的,如果要构建多个工具,那么
itertools.groupby
可能会更好:

from itertools import groupby

lst1_set = set(lst1)  # faster lookups
lst2.sort()  # groupby must operate on a sorted list
lst3 = [(prefix, values) for prefix,values in groupby(
    lst2, lambda s: s.split('_')[0]) if prefix in lst1_set
事实上,该示例说明了一个可能更适合您的不同过程:

lst1_set = set(lst1)  # set lookups are O(1)
lst3 = []
for s in lst2:
    prefix = s.split("_")[0]
    if prefix in lst1_set:
        lst3.append((prefix, s))

我不确定它会减慢多少速度,但一种简单易懂的方法是:

def pair(a,b): 
    c = ''.join(b.split('_processed'))
    return a == c
lst3 = [[x,y] for x in lst1 for y in lst2 if pair(x,y)]
不过,与其他答案相比,实现可能要慢一点

不用(请原谅)试图编写实际的Python代码来演示我的想法,在这种情况下应用的另一个好策略是使用关联数组。(即“字典”)

首先,在
lst1
中循环,为在字典中找到的每个键创建一个虚拟条目

现在,分别循环执行
lst2
。将字符串
file2\u processed
拆分为
file2
processed
。现在,看看第一部分(“file2”)是否在字典中。(如果没有,为什么没有?)将第二部分(“已处理”)存储到字典条目槽中

Python字典是专门为生成与任何键关联的(一)值而设计的。。。很快。。。或者得出这样一个条目不存在的结论。在几乎所有编程语言中,这通常是避免搜索的一个非常好的策略


然后,您可以迭代字典中的所有
,或迭代“键及其关联值”,以生成最终结果。请注意,不会按任何特定顺序生成密钥。

列表将为空,因为
file1.txt
不在
file1\u processed.txt
中。欢迎使用StackOverflow!这段代码有一些非常强烈的代码味道。您是否考虑过使用类来存储您的状态,而不必进行字符串解析?您是否总是尝试在
lst2
中为
中的文件
.txt
匹配
lst1
中的
.txt
?它是否总是像添加一个
\u处理的
一样简单?这些列表之间的关系如何?
lst1
中的每个文件是否都有已处理的文件?还是仅仅为了一些?对于不在
lst1
中的文件,是否存在已处理的文件?你真的需要添加更多的信息;否则,我会假设我可以在一次过程中从
lst1
生成
lst2
。当然,我不会进行简单的搜索,而是使用os.path.splitext。这个函数只是对我实际工作的一个基本解释。根据我们掌握的信息,你所做的基本上和它得到的一样有效。然而,首先知道如何构建这些列表是非常重要的,因为在该阶段可能会应用一个微不足道的优化,这将使该操作更加高效。使用itertools不会神奇地使二次计算变为非二次计算。您只是在顶部添加了一些味道来隐藏这两个循环。对于较大的输入列表,结果列表将同样大(根据所需结果列表的定义)。@poke,正确,但只要不将结果放入另一个列表中,它将消除较大的输出。