Python:哪个更快:匹配列表或匹配词典?

时间:2013-01-26 21:07:03

标签: python list dictionary match

我有两个大清单。每个都包含列表:

list_1 = [[1, "BMW", "Boston", "01Jan2013"], [37, "Chevrolet", "Denver", "05Jan2013"],
[854, "BMW", "Boston", "01Jan2013"],...]

list_2 = [[1, "Mercedes", "Boston", "01Jan2013"], [37, "Chevrolet", "Denver", "05Jan2013"],
[854, "Toyota", "Boston", "01Jan2013"],...]

内部列表始终具有相同的项目类型。

现在我想使用内部列表的第1项,第3项和第4项,将list_1中的每个内部与list_2中的内部匹配。即:序列号,城市来源和日期。这些键始终与list_2相同。 list_1中的内部列表在list_2中只能有0或1个匹配。

什么是最pythonic和最快的方法?我应该将列表转换为字典吗?

5 个答案:

答案 0 :(得分:3)

假设list_1不能包含重复项(根据您的评论),您可以将其转换为set tuple而不是列表。这样,您可以使用in运算符有效地检查某个项目是否在集合中。

您需要使用元组而不是列表,因为列表是可变的(因此不可清除),因此无法将它们放入set。如果您使用dict,则同样适用,但set似乎更适合您的用例(不清楚您使用什么作为dict的关键字)

答案 1 :(得分:2)

在速度方面,您可能想要使用字典。看来,无论如何,您需要遍历列表。字典当然比迭代列表更快,因此您可以将至少一个列表放入字典中。 (我在两个单独的列表中测试了以下200,000个条目的解决方案,我的速度平均为0.109999秒完成。列表超出了那个标记。)如果你只是尝试使用列表,你可能不会接近这个或元组,除非您的条目顺序允许您使用像zip这样的东西。您的序列号似乎是唯一的,因此以下方法可行(通过迭代一个列表,然后将项目1,3和4 [位置0,2和3]与字典中的值进行比较):

list_1 = [[1, "BMW", "Boston", "01Jan2013"], [37, "Chevrolet", "Denver", "05Jan2013"],
[854, "BMW", "Boston", "01Jan2013"]]

list_2 = [[1, "Mercedes", "Boston", "01Jan2013"], [37, "Chevrolet", "Denver", "05Jan2013"],
[854, "Toyota", "Boston", "01Jan2013"]]


dict_2 = dict()

for elem in list_2:
    dict_2[elem[0]] = elem[1:]

for item in list_1:
    if dict_2[item[0]][1:] == item[2:]:    # Have to offset the index since dict list only has three elements
        print item


[1, 'BMW', 'Boston', '01Jan2013']
[37, 'Chevrolet', 'Denver', '05Jan2013']
[854, 'BMW', 'Boston', '01Jan2013']

将第二个列表转换为字典后,您只需迭代一个列表即可获得结果。此解决方案将返回list_1中每个匹配项的整个子列表,您似乎需要它。如果您想要两个列表中的完整匹配子列表,这将起作用:

for item in list_1:
    if dict_2[item[0]][1:] == item[2:]:
        print item, [item[0]] + dict_2[item[0]]


[1, 'BMW', 'Boston', '01Jan2013'] [1, 'Mercedes', 'Boston', '01Jan2013']
[37, 'Chevrolet', 'Denver', '05Jan2013'] [37, 'Chevrolet', 'Denver', '05Jan2013']
[854, 'BMW', 'Boston', '01Jan2013'] [854, 'Toyota', 'Boston', '01Jan2013']

答案 2 :(得分:1)

您可以通过以下方式定义指定要比较的字段的键功能:

def item_key(item):
    return tuple(item[i] for i in [0, 2, 3])

它应该是可清除的,以便您可以将其用作dict键。 您可以创建从项目键到项目本身的映射,或者如果不同的项目可以共享相同的键,则可以创建项目列表。

key_to_item2 = dict((item_key(item), item) for item in list2)

现在,您可以针对字典测试 list1 中的每个项目。

for item1 in list1:
    item2 = key_to_item2.get(item_key(item1))
    if item2 is None:
        # no match found
    else:
        # item2 in list2 matches item1 in list1

可以轻松调整此方法,以便使用其他字段进行匹配和支持多个匹配。

答案 3 :(得分:1)

什么是“最佳”解决方案取决于您的需求。如果是速度,那么根据输入的大小,字典可能是最好的主意。

如果它是关于清晰和简洁的话,我认为保持列表并执行以下操作是非常pythonic:

result = []
for l1 in list1:
    result.append([l2 for l2 in list2
                   if l1[0] == l2[0] and l1[2] == l2[2] and l1[3] == l2[3]])
    assert(len(result[-1]) in [0,1])

答案 4 :(得分:1)

类似于@omz的解决方案是将列表转换为字典。 dict键是元组(serial,city,date)(第1,3和4项),值将是另一个字段'make'(第2项)。然后匹配它们,只需遍历list_1(现在为dict_1)的键,尝试检索dict_2的相应成员:

dict_1 = {(1, "Boston", "01Jan2013"):"BMW", (37, "Denver", "05Jan2013"):"Chevrolet", (854, "Boston", "01Jan2013"):"BMW",...}

dict_2 = {(1, "Boston", "01Jan2013"):"Mercedes", (37, "Denver", "05Jan2013"):"Chevrolet", (854, "Boston", "01Jan2013"):"Toyota",...}

for k in dict_1:
    match = dict_2.get (k, None)
    if match is not None:
        print "Match found:", match
    else:
        print "No match"

当然,当你找到匹配时你所做的不是我写的,但这应该用来展示你如何找到匹配。