根据两个值在列表中组合字典
Combine dictionaries in a list based on two values
我希望在词典列表中合并词典。
我的字典列表如下所示:
opt = [{'expiry': '2020-06-26', 'strike': 138.5, 'p_bid': 0.4375, 'p_ask': 0.46875},
{'expiry': '2020-06-26', 'strike': 139.0, 'p_bid': 0.6875, 'p_ask': 0.71875},
{'expiry': '2020-07-22', 'strike': 139.0, 'p_bid': 1.015625, 'p_ask': 1.0625},
{'expiry': '2020-06-26', 'strike': 138.5, 'c_bid': 0.6875, 'c_ask': 0.734375},
{'expiry': '2020-06-26', 'strike': 139.0, 'c_bid': 0.4375, 'c_ask': 0.484375},
{'expiry': '2020-07-22', 'strike': 139.0, 'c_bid': 0.28125, 'c_ask': 0.3125}]
字典需要成对组合,其中 'expiry' 和 'strike' 相同。
所需的输出如下所示:
[{'expiry': '2020-06-26', 'strike': 138.5, 'p_bid': 0.4375, 'p_ask': 0.46875, 'c_bid': 0.6875, 'c_ask': 0.734375},
{'expiry': '2020-06-26', 'strike': 139.0, 'p_bid': 0.6875, 'p_ask': 0.71875, 'c_bid': 0.4375, 'c_ask': 0.484375},
{'expiry': '2020-07-22', 'strike': 139.0, 'p_bid': 1.015625, 'p_ask': 1.0625, 'c_bid': 0.28125, 'c_ask': 0.3125}}]
一个相当简单的方法是使用 pandas:
df = pd.DataFrame(opt)
df = df.drop_duplicates(subset = ["expiry", "strike"])
[ v.dropna().to_dict() for k,v in df.iterrows() ]
结果:
[{'expiry': '2020-06-26', 'strike': 138.5, 'p_bid': 0.4375, 'p_ask': 0.46875},
{'expiry': '2020-06-26', 'strike': 139.0, 'p_bid': 0.6875, 'p_ask': 0.71875},
{'expiry': '2020-07-22', 'strike': 139.0, 'p_bid': 1.015625, 'p_ask': 1.0625}]
请注意,删除重复项时,我会保留第一个元素。如果你想要的话,可以很容易地留下最后一个元素,但是使用:
df = df.drop_duplicates(subset = ["expiry", "strike"], keep="last")
在这种情况下,结果是:
[{'expiry': '2020-06-26', 'strike': 138.5, 'c_bid': 0.6875, 'c_ask': 0.734375},
{'expiry': '2020-06-26', 'strike': 139.0, 'c_bid': 0.4375, 'c_ask': 0.484375},
{'expiry': '2020-07-22', 'strike': 139.0, 'c_bid': 0.28125, 'c_ask': 0.3125}]
另一种方法是使用字典来减少 'similar' 值:
reduction_dict = {(x["expiry"], x["strike"]):x for x in opt }
list(reduction_dict.values())
"Naive" 方法:
将字典添加到新的结果列表中。对于每个新的字典,检查它是否与列表中已有的字典匹配。如果是这样,请合并它们。如果没有,将其添加到列表中:
res = [opt[0]]
for d_new in opt[1:]:
for d in res:
if d['expiry'] == d_new['expiry'] and d['strike'] == d_new['strike']:
#if (d['expiry'], d['strike']) == (d_new['expiry'], d_new['strike']):
d.update(d_new)
break
else:
res.append(d_new)
这里使用了 for/else
结构,它在这里很有用,因为我们只想在列表中添加一个新的字典,如果它与结果列表中的任何其他字典都不匹配。如果我们找到匹配项,我们将合并它们并且 break
和 else
将不会被执行。
略有改善:
上述方法导致每个字典循环所有字典的时间复杂度为 O(n^2)
(不准确,但学术上这仍然是 O(n^2)
)。为了尝试改进这一点,第二种方法可以是一次性将具有相似 expiry
和 strike
的字典组合在一起 (O(n)
):
from collections import defaultdict
merged_dicts = defaultdict(dict)
for d in opt:
merged_dicts[(d['expiry'], d['strike'])].update(d)
res = list(merged_dicts.values())
这使用 collections.defaultdict
to easily merge the dicts without too many if
conditions. We also use dict
's update
方法实际合并它们。
我希望在词典列表中合并词典。 我的字典列表如下所示:
opt = [{'expiry': '2020-06-26', 'strike': 138.5, 'p_bid': 0.4375, 'p_ask': 0.46875},
{'expiry': '2020-06-26', 'strike': 139.0, 'p_bid': 0.6875, 'p_ask': 0.71875},
{'expiry': '2020-07-22', 'strike': 139.0, 'p_bid': 1.015625, 'p_ask': 1.0625},
{'expiry': '2020-06-26', 'strike': 138.5, 'c_bid': 0.6875, 'c_ask': 0.734375},
{'expiry': '2020-06-26', 'strike': 139.0, 'c_bid': 0.4375, 'c_ask': 0.484375},
{'expiry': '2020-07-22', 'strike': 139.0, 'c_bid': 0.28125, 'c_ask': 0.3125}]
字典需要成对组合,其中 'expiry' 和 'strike' 相同。 所需的输出如下所示:
[{'expiry': '2020-06-26', 'strike': 138.5, 'p_bid': 0.4375, 'p_ask': 0.46875, 'c_bid': 0.6875, 'c_ask': 0.734375},
{'expiry': '2020-06-26', 'strike': 139.0, 'p_bid': 0.6875, 'p_ask': 0.71875, 'c_bid': 0.4375, 'c_ask': 0.484375},
{'expiry': '2020-07-22', 'strike': 139.0, 'p_bid': 1.015625, 'p_ask': 1.0625, 'c_bid': 0.28125, 'c_ask': 0.3125}}]
一个相当简单的方法是使用 pandas:
df = pd.DataFrame(opt)
df = df.drop_duplicates(subset = ["expiry", "strike"])
[ v.dropna().to_dict() for k,v in df.iterrows() ]
结果:
[{'expiry': '2020-06-26', 'strike': 138.5, 'p_bid': 0.4375, 'p_ask': 0.46875},
{'expiry': '2020-06-26', 'strike': 139.0, 'p_bid': 0.6875, 'p_ask': 0.71875},
{'expiry': '2020-07-22', 'strike': 139.0, 'p_bid': 1.015625, 'p_ask': 1.0625}]
请注意,删除重复项时,我会保留第一个元素。如果你想要的话,可以很容易地留下最后一个元素,但是使用:
df = df.drop_duplicates(subset = ["expiry", "strike"], keep="last")
在这种情况下,结果是:
[{'expiry': '2020-06-26', 'strike': 138.5, 'c_bid': 0.6875, 'c_ask': 0.734375},
{'expiry': '2020-06-26', 'strike': 139.0, 'c_bid': 0.4375, 'c_ask': 0.484375},
{'expiry': '2020-07-22', 'strike': 139.0, 'c_bid': 0.28125, 'c_ask': 0.3125}]
另一种方法是使用字典来减少 'similar' 值:
reduction_dict = {(x["expiry"], x["strike"]):x for x in opt }
list(reduction_dict.values())
"Naive" 方法:
将字典添加到新的结果列表中。对于每个新的字典,检查它是否与列表中已有的字典匹配。如果是这样,请合并它们。如果没有,将其添加到列表中:
res = [opt[0]]
for d_new in opt[1:]:
for d in res:
if d['expiry'] == d_new['expiry'] and d['strike'] == d_new['strike']:
#if (d['expiry'], d['strike']) == (d_new['expiry'], d_new['strike']):
d.update(d_new)
break
else:
res.append(d_new)
这里使用了 for/else
结构,它在这里很有用,因为我们只想在列表中添加一个新的字典,如果它与结果列表中的任何其他字典都不匹配。如果我们找到匹配项,我们将合并它们并且 break
和 else
将不会被执行。
略有改善:
上述方法导致每个字典循环所有字典的时间复杂度为 O(n^2)
(不准确,但学术上这仍然是 O(n^2)
)。为了尝试改进这一点,第二种方法可以是一次性将具有相似 expiry
和 strike
的字典组合在一起 (O(n)
):
from collections import defaultdict
merged_dicts = defaultdict(dict)
for d in opt:
merged_dicts[(d['expiry'], d['strike'])].update(d)
res = list(merged_dicts.values())
这使用 collections.defaultdict
to easily merge the dicts without too many if
conditions. We also use dict
's update
方法实际合并它们。