遍历两个字典列表并创建无循环的元组列表

时间:2019-03-28 14:25:57

标签: python

我有两个字典列表:list1list2

print(list1)
[{'name': 'fooa', 'desc': 'bazv', 'city': 1, 'ID': 1},
 {'name': 'bard', 'desc': 'besd', 'city': 2, 'ID': 1},
 {'name': 'baer', 'desc': 'bees', 'city': 2, 'ID': 1},
 {'name': 'aaaa', 'desc': 'bnbb', 'city': 1, 'ID': 2},
 {'name': 'cgcc', 'desc': 'dgdd', 'city': 1, 'ID': 2}]

print(list2)
[{'name': 'foo', 'desc': 'baz', 'city': 1, 'ID': 1},
 {'name': 'bar', 'desc': 'bes', 'city': 1, 'ID': 1},
 {'name': 'bar', 'desc': 'bes', 'city': 2, 'ID': 1},
 {'name': 'aaa', 'desc': 'bbb', 'city': 1, 'ID': 2},
 {'name': 'ccc', 'desc': 'ddd', 'city': 1, 'ID': 2}]

我需要一个元组列表,其中将包含两个成对的字典(每个列表中有一个字典),它们具有相同的cityID

我是用双循环做的:

list_of_tuples = []
for i in list1:
    for j in list2:
        if i['ID'] == j['ID'] and i['city'] == j['city']:
            list_of_tuples.append((i, j))
print(list_of_tuples)

[({'name': 'fooa', 'desc': 'bazv', 'city': 1, 'ID': 1},
  {'name': 'foo', 'desc': 'baz', 'city': 1, 'ID': 1}),
 ({'name': 'fooa', 'desc': 'bazv', 'city': 1, 'ID': 1},
  {'name': 'bar', 'desc': 'bes', 'city': 1, 'ID': 1}),
 ({'name': 'bard', 'desc': 'besd', 'city': 2, 'ID': 1},
  {'name': 'bar', 'desc': 'bes', 'city': 2, 'ID': 1}),
 ({'name': 'baer', 'desc': 'bees', 'city': 2, 'ID': 1},
  {'name': 'bar', 'desc': 'bes', 'city': 2, 'ID': 1}),
 ({'name': 'aaaa', 'desc': 'bnbb', 'city': 1, 'ID': 2},
  {'name': 'aaa', 'desc': 'bbb', 'city': 1, 'ID': 2}),
 ({'name': 'aaaa', 'desc': 'bnbb', 'city': 1, 'ID': 2},
  {'name': 'ccc', 'desc': 'ddd', 'city': 1, 'ID': 2}),
 ({'name': 'cgcc', 'desc': 'dgdd', 'city': 1, 'ID': 2},
  {'name': 'aaa', 'desc': 'bbb', 'city': 1, 'ID': 2}),
 ({'name': 'cgcc', 'desc': 'dgdd', 'city': 1, 'ID': 2},
  {'name': 'ccc', 'desc': 'ddd', 'city': 1, 'ID': 2})]

问题:如何以更Python化的方式(无循环)执行此操作?

3 个答案:

答案 0 :(得分:5)

您可以使用itertools.productfilter

from itertools import product


list1 = [{'name': 'fooa', 'desc': 'bazv', 'city': 1, 'ID': 1},
         {'name': 'bard', 'desc': 'besd', 'city': 2, 'ID': 1},
         {'name': 'baer', 'desc': 'bees', 'city': 2, 'ID': 1},
         {'name': 'aaaa', 'desc': 'bnbb', 'city': 1, 'ID': 2},
         {'name': 'cgcc', 'desc': 'dgdd', 'city': 1, 'ID': 2}]

list2 = [{'name': 'foo', 'desc': 'baz', 'city': 1, 'ID': 1},
         {'name': 'bar', 'desc': 'bes', 'city': 1, 'ID': 1},
         {'name': 'bar', 'desc': 'bes', 'city': 2, 'ID': 1},
         {'name': 'aaa', 'desc': 'bbb', 'city': 1, 'ID': 2},
         {'name': 'ccc', 'desc': 'ddd', 'city': 1, 'ID': 2}]

def condition(x):
    return x[0]['ID'] == x[1]['ID'] and x[0]['city'] == x[1]['city']

list_of_tuples = list(filter(condition, product(list1, list2)))

答案 1 :(得分:3)

这是一个非常适合pandas的问题。如果将列表转换为DataFrame,则匹配IDcity上的记录与inner join of the two DataFrames相同。

import pandas as pd

# convert lists to DataFrames
df1 = pd.DataFrame(list1)
df2 = pd.DataFrame(list2)

# merge the two DataFrames
print(df1.merge(df2, on=["ID", "city"]))
#   ID  city desc_x name_x desc_y name_y
#0   1     1   bazv   fooa    baz    foo
#1   1     1   bazv   fooa    bes    bar
#2   1     2   besd   bard    bes    bar
#3   1     2   bees   baer    bes    bar
#4   2     1   bnbb   aaaa    bbb    aaa
#5   2     1   bnbb   aaaa    ddd    ccc
#6   2     1   dgdd   cgcc    bbb    aaa
#7   2     1   dgdd   cgcc    ddd    ccc

现在,每行中都有匹配的记录。由于descname列都存在(并且不用于合并),因此它们分别用_x_y下标,以区分两个源DataFrame。

您只需要重新格式化它即可在所需的输出中使用。您可以使用to_dict和列表理解来实现这一点:

list_of_tuples = [
    (
        {"name": r["name_x"], "desc": r["desc_x"], "city": r["city"], "ID": r["ID"]},
        {"name": r["name_y"], "desc": r["desc_y"], "city": r["city"], "ID": r["ID"]}
    ) for r in df1.merge(df2, on=["ID", "city"]).to_dict(orient="records")
]

print(list_of_tuples)
#[({'ID': 1, 'city': 1, 'desc': 'bazv', 'name': 'fooa'},
#  {'ID': 1, 'city': 1, 'desc': 'baz', 'name': 'foo'}),
# ({'ID': 1, 'city': 1, 'desc': 'bazv', 'name': 'fooa'},
#  {'ID': 1, 'city': 1, 'desc': 'bes', 'name': 'bar'}),
# ({'ID': 1, 'city': 2, 'desc': 'besd', 'name': 'bard'},
#  {'ID': 1, 'city': 2, 'desc': 'bes', 'name': 'bar'}),
# ({'ID': 1, 'city': 2, 'desc': 'bees', 'name': 'baer'},
#  {'ID': 1, 'city': 2, 'desc': 'bes', 'name': 'bar'}),
# ({'ID': 2, 'city': 1, 'desc': 'bnbb', 'name': 'aaaa'},
#  {'ID': 2, 'city': 1, 'desc': 'bbb', 'name': 'aaa'}),
# ({'ID': 2, 'city': 1, 'desc': 'bnbb', 'name': 'aaaa'},
#  {'ID': 2, 'city': 1, 'desc': 'ddd', 'name': 'ccc'}),
# ({'ID': 2, 'city': 1, 'desc': 'dgdd', 'name': 'cgcc'},
#  {'ID': 2, 'city': 1, 'desc': 'bbb', 'name': 'aaa'}),
# ({'ID': 2, 'city': 1, 'desc': 'dgdd', 'name': 'cgcc'},
#  {'ID': 2, 'city': 1, 'desc': 'ddd', 'name': 'ccc'})]

答案 2 :(得分:1)

具有嵌套循环不是“非pythonic”。但是,您可以通过列表理解获得相同的结果。我不认为它更具可读性:

[(i, j) for j in list2 for i in list1 if i['ID'] == j['ID'] and i['city'] == j['city']]