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,正确,但只要不将结果放入另一个列表中,它将消除较大的输出。