Python3:根据子字符串在两个列表之间匹配元素

时间:2019-03-14 06:20:55

标签: python python-3.x list-comprehension dictionary-comprehension

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

    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来完成,但这似乎有点复杂。我可以编写一个原始循环,但这似乎并不是特别有效。

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

2 个答案:

答案 0 :(得分:1)

您可以按照建议运行 [DataContract] public class StringValueObject { public string Value { get; set; } } StringValueObject result = JsonConvert.DeserializeObject<StringValueObject>("\"Hello world!\""); 并检查第一个列表元素的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]}

答案 1 :(得分:0)

理解只是编写collection-building-loops的一种简单方法。眼睛更容易,不一定有效。

在@ 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

以下版本的速度更快,大约1毫秒:

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进行比较来保持第一个匹配项。