具有如下对象:
{
"pick": "a",
"elements": [
{"id": "a", "label": "First"},
{"id": "b", "label": "Second"}
]
}
如何在elements
等于id
的值的pick
列表中检索项目?
我正在尝试类似的事情:
elements[?id == pick]
但是,显然,比较器右侧的表达式是根据我的过滤器表达式相对于要测试的对象求值的。
如何实现我想要的?如果无法立即使用,您对我应该在哪里扩展JMESPath提出任何建议?谢谢!
答案 0 :(得分:2)
不幸的是, JMESPath 不允许引用父元素。
要避免这种限制,在这种简单情况下,您可以:
实际上,多亏了 f-strings ,最后两个步骤可以在 一条指令,因此代码可以是:
pck = jmespath.search('pick', dct)
jmespath.search(f'elements[?id == `{pck}`]', dct)
其中 dct 是源JSON对象。
如果您的案件比较复杂(例如,许多此类元素,而 pick 值),则应使用其他工具。
一个非常有趣的选择是使用 Pandas 软件包。
假设您的源词典包含:
dct = {
"x1": {
"pick": "a",
"elements": [
{"id": "a", "label": "First_a"},
{"id": "b", "label": "Second_a"},
{"id": "c", "label": "Third_a"}
]
},
"x2": {
"pick": "b",
"elements": [
{"id": "a", "label": "First_b"},
{"id": "b", "label": "Second_b"},
{"id": "c", "label": "Third_b"}
]
}
}
要做的第一件事是将 dct 转换为 Pandas DataFrame:
import pandas as pd
df = pd.DataFrame.from_dict(dct, orient='index')
结果(以“缩写”形式打印)为:
pick elements
x1 a [{'id': 'a', 'label': 'First_a'}, {'id': 'b', ...
x2 b [{'id': 'a', 'label': 'First_b'}, {'id': 'b', ...
说明(如果您没有 Pandas 的经验):
此形状不是很有用,所以让我们爆炸 元素列:
df = df.explode('elements')
现在 df 包含:
pick elements
x1 a {'id': 'a', 'label': 'First_a'}
x1 a {'id': 'b', 'label': 'Second_a'}
x1 a {'id': 'c', 'label': 'Third_a'}
x2 b {'id': 'a', 'label': 'First_b'}
x2 b {'id': 'b', 'label': 'Second_b'}
x2 b {'id': 'c', 'label': 'Third_b'}
此形状更接近我们需要的形状:每个源行均已分为 几行,每行都与初始列表中的分开项。
还有另一件事要做,即创建一个包含 id 值的列, 稍后与 pick 列进行比较。为此,请运行:
df['id'] = df.elements.apply(lambda dct: dct['id'])
现在 df 包含:
pick elements id
x1 a {'id': 'a', 'label': 'First_a'} a
x1 a {'id': 'b', 'label': 'Second_a'} b
x1 a {'id': 'c', 'label': 'Third_a'} c
x2 b {'id': 'a', 'label': 'First_b'} a
x2 b {'id': 'b', 'label': 'Second_b'} b
x2 b {'id': 'c', 'label': 'Third_b'} c
要获得最终结果,您应该:
执行此操作的代码是:
df.query('pick == id').elements
给予:
x1 {'id': 'a', 'label': 'First_a'}
x2 {'id': 'b', 'label': 'Second_b'}
在 Pandas 中,它是一个 Series (假设每个元素都有一个列表 带有索引的“标签”。
现在您可以将其隐藏到字典或任何您想要的东西上。