[英]Iterate over two lists of dicts and create list of tuples without loop
I have two lists of dicts: list1
and list2
. 我有两个dicts列表:
list1
和list2
。
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}]
I need a list of tuples that will hold two paired dicts (one dict from each list) with the same city
and ID
. 我需要一个元组列表,它将包含两个配对的dicts(每个列表中的一个dict),具有相同的
city
和ID
。
I did it with double loop: 我用双循环做到了:
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})]
Question: How to do this in a more pythonic way (without loops)? 问题:如何以更加pythonic的方式(没有循环)这样做?
You can use itertools.product
and filter
: 您可以使用
itertools.product
和filter
:
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)))
This is a problem well suited for pandas
. 这是一个非常适合
pandas
的问题。 If you convert the lists to DataFrames, matching the records on ID
and city
is the same as an inner join of the two DataFrames . 如果将列表转换为DataFrame,则匹配
ID
和city
上的记录与两个DataFrame的内部联接相同 。
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
Now you have the matched records in each row. 现在,每行都有匹配的记录。 Since the
desc
and name
columns were present in both (and not used for the merge), they get subscripted with _x
and _y
to differentiate between the two souce DataFrames. 由于
desc
和name
列存在于两者中(并且不用于合并),因此它们使用_x
和_y
进行下标以区分两个源DataFrame。
You just need to reformat it to be in your desired output. 您只需将其重新格式化为所需的输出即可。 You can achieve this using
to_dict
and a list comprehension: 你可以使用
to_dict
和列表理解来实现这个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'})]
Having nested loops is not "not pythonic". 嵌套循环不是“不是pythonic”。 However, you can achieve the same result with a list comprehension.
但是,您可以使用列表推导实现相同的结果。 I don't think it's more readable though:
我不认为它更具可读性:
[(i, j) for j in list2 for i in list1 if i['ID'] == j['ID'] and i['city'] == j['city']]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.