Python3:基于子串的两个列表之间的匹配元素

问题描述 投票:1回答:2

这个问题是关于在一个列表中匹配字符串与另一个列表中的匹配字符串。我试图找出做这种匹配的最佳方法。我下面的例子很小,但我必须将相同的想法应用到更大的列表中。所以我在一个列表中有一组文件名和路径,然后我在另一个列表中有一个部分文件名列表,例如:

    list1 = ['/../../abc_file1.txt',
             '/../../abc_extrafile1.txt',
             '/../../abc_file2.txt',
             '/../../abc_file3.txt',
             '/../../abc_extrafile3.txt']

然后我有一个不同的列表

    ['file1', 'extrafile1', 'file2', 'file3', 'extrafile3']

所以我想做的是获得一个生成字典的匹配:

    {'file1': '/../../abc_file1.txt',
     'extrafile1': '/../../abc_extrafile1.txt',
     'file2': '/../../abc_file2.txt',
     'file3': '/../../abc_file3.txt',
     'extrafile3': '/../../abc_extrafile3.txt'}

所以文件名之间有一些重叠,我需要小心。

有很多方法可以做这样的事情,但我不确定哪种方法最适合匹配1000或10,000个条目的列表。似乎这可能是通过字典理解或lambda完成的,但似乎有点复杂。我可以写一个原始循环,但这似乎并不特别有效。

有关如何管理此类匹配问题的任何建议。

python python-3.x list-comprehension dictionary-comprehension
2个回答
1
投票

您可以按照建议运行dict comprehension,并检查第一个列表元素的split(考虑重叠)并删除扩展:

list1 = ['/../../abc_file1.txt',
             '/../../abc_extrafile1.txt',
             '/../../abc_file2.txt',
             '/../../abc_file3.txt',
             '/../../abc_extrafile3.txt']

list2 = ['file1', 'extrafile1', 'file2', 'file3', 'extrafile3']

my_dict = {k: v for v in list1 for k in list2 if k == v.split('_')[1][:-4]}

输出:

{'file1': '/../../abc_file1.txt', 'extrafile1': '/../../abc_extrafile1.txt', 'file2': '/../../abc_file2.txt', 'file3': '/../../abc_file3.txt', 'extrafile3': '/../../abc_extrafile3.txt'}

0
投票

理解只是编写集合构建循环的一种更简单的方法。更容易看到,不一定有效。

在@ matt-b答案中,dict comprehension隐藏了一个双for循环,使得大型列表(n平方复杂度)的理解相当慢。

您可以通过简单的循环解决您的具体问题,保持复杂性线性。

有了这个输入:

size = 1000
list1 = [ '/../../abc_file' + str(i) + '.txt' for i in range(size) ]
list2 = [ 'file' + str(i) for i in range(size) ]

dict comprehension在我的机器上大约需要500毫秒:

my_dict = {k: v for v in list1 for k in list2 if k == v.split('_')[1][:-4]}

# 1 loop, best of 3: 516 ms per loop

以下版本更快,大约1ms:

res = { k: None for k in list2 }
for v in list1:
    name = v.split('_')[-1][:-4]
    if name in res:
        res[name] = v

# 100 loops, best of 3: 1.15 ms per loop

使用这种结构,如果需要,很容易保持多个匹配:

res = { k: [] for k in list2 }
for v in list1:
    name = v.split('_')[-1][:-4]
    if name in res:
        res[name].append(v)

# 100 loops, best of 3: 1.54 ms per loop

您还可以通过检查res[name]的当前None值来保持第一场比赛。

© www.soinside.com 2019 - 2024. All rights reserved.