提问人:tautology 提问时间:9/21/2023 更新时间:9/22/2023 访问量:65
从多个字典列表中有条件地提取数据的大多数 Python 方法
Most Pythonic method of conditionally extracting data from multiple lists of dictionaries
问:
我正在尝试使用两个字典列表来构建一个对象,这些字典是从与两个不同数据库的TAP连接构建的。由于数据源的原因,我不能保证任何词典都会包含我需要的信息,所以我选择了一本主要词典,如果信息不在那里,那么我就从第二本词典中提取它。
由于我从两个不同的数据源中提取数据,因此两个源的 TAP 中的字段名称不同,因此我不能只对字典进行交集。
目前我可以让它工作,但我对解决方案不满意:
for result in eeuresults:
name=result['target_name']
axes=result['semi_major_axis']
period=result['period']
radius=result['radius']
if math.isnan(period):
for r in eparesults:
if r['pl_name'] == name: period=r['pl_orbper']
if math.isnan(axes):
for r in eparesults:
if r['pl_name'] == name: axes=r['pl_orbsmax']
if math.isnan(radius):
for r in eparesults:
if r['pl_name'] == name: radius=r['pl_radj']
我尝试使用 dictionary.get() 来简化它,但如果该值不在第二个字典列表中,它就会下降。
axes=result.get('semi_major_axis',[r['pl_orbper'] for r in eparesults if r['pl_name']==name][0])
答:
1赞
rioV8
9/21/2023
#1
删除代码重复
def find_in_eparesults(name, value, epa_key):
if math.isnan(value):
for r in eparesults:
if r['pl_name'] == name:
value = r[epa_key]
break
return value
for result in eeuresults:
name=result['target_name']
axes=find_in_eparesults(name, result['semi_major_axis'], 'pl_orbper')
period=find_in_eparesults(name, result['period'], 'pl_orbsmax')
radius=find_in_eparesults(name, result['radius'], 'pl_radj')
评论
0赞
Swifty
9/21/2023
我会通过使用字典 {result_key: epa_key} 来进一步推动它
0赞
rioV8
9/21/2023
@Swifty如果他不在其他任何地方使用映射,那么字典就矫枉过正了
2赞
Andrej Kesely
9/21/2023
#2
我建议将 转换为 a 以使搜索更容易:eparesults
dict
eeuresults = [
{"target_name": "A", "semi_major_axis": 1, "period": 2},
{"target_name": "B", "period": 3, "radius": 4},
]
eparesults = [
{"pl_name": "A", "pl_orbper": 1, "pl_orbsmax": 2, "pl_radj": 3},
{"pl_name": "B", "pl_orbper": 4, "pl_orbsmax": 5, "pl_radj": 6},
]
# This is the important part, convert `eparesults` to a dict:
eparesults_dict = {d["pl_name"]: d for d in eparesults}
for result in eeuresults:
name = result["target_name"]
axes = result.get("semi_major_axis", eparesults_dict.get(name, {}).get("pl_orbper"))
period = result.get("period", eparesults_dict.get(name, {}).get("pl_orbsmax"))
radius = result.get("radius", eparesults_dict.get(name, {}).get("pl_radj"))
print(f"{name=} {axes=} {period=} {radius=}")
指纹:
name='A' axes=1 period=2 radius=3
name='B' axes=4 period=3 radius=4
评论
1赞
tautology
9/22/2023
这似乎是一个比我所拥有的更干净的解决方案 - 我喜欢双重使用 .get() 来减少循环和条件!
0赞
tautology
9/22/2023
将此转录到我的脚本中,我还注意到我pl_orbper并pl_orbsmax错误的方式,所以你不小心发现我可能使用了错误的数据(它们两个字段是相关的,所以还不错)!
1赞
Marcin Tamiński
9/22/2023
#3
这样的事情怎么样?
from collections import defaultdict
from math import nan, isnan
class Result(object):
def __getattr__(self, name):
return nan
def __setattr__(self, name, value):
if isnan(value):
return
super().__setattr__(name, value)
def __iter__(self):
return iter((self.axes, self.period, self.radius))
results = defaultdict(Result)
for d in eeuresults:
r = results[d['target_name']]
r.axes = d['semi_major_axis']
r.period = d['period']
r.radius = d['radius']
for d in eparesults:
r = results[d['pl_name']]
r.axes = d['pl_orbsmax']
r.period = d['pl_orbper']
r.radius = d['pl_radj']
# In case you would need to lookup keys yourself, conversion to dict is needed.
# results = dict(results)
for name, (axes, period, radius) in results.items():
print(f"{name=} {axes=} {period=} {radius=}")
只要您知道它们的密钥,这可以包含任意数量的列表。
此外,如果您想要除 .__setattr__
isnan
如果您预计任何字典中缺少密钥,请将 d['key']
替换为 d.get('key', nan)
评论
0赞
tautology
9/22/2023
这绝对是一种有趣而优雅的解决方式;尽管使用新对象有点矫枉过正,然后我需要从字典中获取我的数据到我当前使用的对象属性。我很喜欢它,但对于这个项目来说有点太多了。
0赞
rioV8
9/22/2023
您的逻辑与 OP 代码不同
评论