我正在尝试找到一种方法来将一个字典的键,值对与另一个字典进行匹配。第一个字典record
是具有不变数量的键的记录(虽然每个键的值当然可以更改),但是第二个字典potential_outputs
是用户定义的,具有可变的键和值。用户从record
中选择要分配的键,给它们分配一个值,然后分配找到匹配项时使用的输出值。
示例:
record = [
{"Name": "John Smith", "Class": "c1", "Plan": "p1",},
{"Name": "Jane Doe", "Class": "c2", "Plan": "p2",},
]
potential_outputs = [
{"Class": "c1", "Plan": "p1", "Output": "o11"},
{"Class": "c1", "Plan": "p2", "Output": "o12"},
{"Class": "c2", "Plan": "p1", "Output": "o21"},
{"Class": "c2", "Plan": "p2", "Output": "o22"},
]
程序需要能够遍历record
列表中的每个字典,确定potential_outputs
中的哪个字典与键,值对匹配,然后从匹配的{ {1}}字典。
预期输出类似于:
potential_outputs
我还想指出,我不致力于使用字典来解决此问题。
谢谢!
答案 0 :(得分:2)
您可以使用(Class, Plan)
元组键对输出进行分组,然后使用列表推导输出找到的输出字典。
使用输出查找字典进行O(1)
查找,可以使解决方案成为O(N + M)
,而不是O(N * M)
,其中N
是{{1}中词典的数目},而record
是M
中词典的数量。
potential_outputs
输出:
record = [
{"Name": "John Smith", "Class": "c1", "Plan": "p1",},
{"Name": "Jane Doe", "Class": "c2", "Plan": "p2",},
]
potential_outputs = [
{"Class": "c1", "Plan": "p1", "Output": "o11"},
{"Class": "c1", "Plan": "p2", "Output": "o12"},
{"Class": "c2", "Plan": "p1", "Output": "o21"},
{"Class": "c2", "Plan": "p2", "Output": "o22"},
]
outputs = {(output["Class"], output["Plan"]): output["Output"] for output in potential_outputs}
result = [{"Name": r["Name"], "Output": outputs[r["Class"], r["Plan"]]} for r in record]
print(result)
答案 1 :(得分:1)
为避免嵌套循环和M * N复杂性,您可以预处理record
from collections import defaultdict
rec = defaultdict(lambda: defaultdict(list))
for r in record:
rec[r['Class']][r['Plan']].append(r['Name'])
在遍历potential_outputs
result = [{"Name": name, "Output": po["Output"]}
for po in potential_outputs
for name in rec[po['Class']][po['Plan']]]
result
# [{'Name': 'John Smith', 'Output': 'o11'}, {'Name': 'Jane Doe', 'Output': 'o22'}]
答案 2 :(得分:1)
可以做到这一点,并且通过创建要用作索引的第三个字典比线性性能更好。 索引字典上的“关键字”应该是关键字/值对的集合,它们可以是所需输出记录的有效标识符。看起来如果您使用包含元组的FrosenSets生成此索引-类似于:
def make_index(data):
result_index = {}
for row in data:
work_row = row.copy()
work_row.pop("Output")
while work_row:
key = frozenset((key, value) for key, value in work_row.items())
result_index.setdefault(key, []).append(row)
work_row.pop(next(iter(work_row)))
return result_index
def search(index, row_key):
row_key = row_key.copy()
row_key.pop("Name", None)
key = frozenset((key, value) for key, value in row_key.items())
return index[key]
如果“ potential_outputs”具有除“名称”之外的所有键,这将起作用:
In [35]: search(index, record[0])
Out[35]: [{'Class': 'c1', 'Plan': 'p1', 'Output': 'o11'}]
In [36]: index = make_index(potential_outputs)
In [37]: search(index, record[0])
Out[37]: [{'Class': 'c1', 'Plan': 'p1', 'Output': 'o11'}]
如果您希望mtches的匹配密钥少于 只是剥离名称,相同的索引有效,但“搜索” 代码必须更改。然后我们必须确切地知道 要查询的匹配项是什么?如果是“ class”并且 “计划”匹配不同的记录,是否都应退回?还是没有? 您可能会在itertools中找到一些东西来生成 给定记录行,您要搜索的所有键。
无论如何,这段代码已经适合 如果一切都匹配,则可以恢复多个结果:
In [39]: search(index, {"Plan": "p2"})
Out[39]:
[{'Class': 'c1', 'Plan': 'p2', 'Output': 'o12'},
{'Class': 'c2', 'Plan': 'p2', 'Output': 'o22'}]
答案 3 :(得分:0)
这是使用pandas
处理该问题的一种非常简单的方法:
import pandas as pd
# Read your list of dicts into DataFrames.
dfr = pd.DataFrame(record)
dfp = pd.DataFrame(potential_outputs)
# Merge the two DataFrames on `Class` and `Plan` and return the result.
result = pd.merge(dfr,
dfp,
how='inner',
on=['Class', 'Plan']).drop(['Class', 'Plan'], axis=1)
作为数据框:
Name Output
0 John Smith o11
1 Jane Doe o22
作为列表:
result2 = [i for i in result.T.to_dict().values()]
[{'Name': 'John Smith', 'Output': 'o11'}, {'Name': 'Jane Doe', 'Output': 'o22'}]
答案 4 :(得分:0)
如果您要使用以下形式使potential_outputs成为字典
{("c1","p1"): "o11"}
,您可以这样做:
result = []
for a in record:
if (a["Class"], a["Plan"]) in potential_outputs:
result.append({"Name": a["Name"], "Output": potential_outputs[(a["Class"], a["Plan"])]})
这可能不是最好的方法,但将是纯Python的方法。
答案 5 :(得分:0)
如果您对单线飞机感兴趣
result = [{"Name": r["Name"], "Output": o["Output"]} for r in record for o in potential_outputs if r["Class"] == o["Class"] and r["Plan"] == o["Plan"]]
答案 6 :(得分:0)
您可以将potential_outputs
重组为字典:
potential_output_dict = {
f"{o['Class']}_{o['Plan']}": o['Output'] for o in potential_outputs
}
output = []
for r in record:
plan_key = f"{r['Class']}_{r['Plan']}"
plan = potential_output_dict.get(plan_key)
if not plan:
continue
output.append({
"Name": r['Name'],
"Plan": plan,
})
print(output)
通过这种方式,您使用get()
比遍历字典列表要好一些。
(代码未经测试)