python - 使用 JMESPath 根据另一个查询结果过滤列表
问题描述
具有如下对象:
{
"pick": "a",
"elements": [
{"id": "a", "label": "First"},
{"id": "b", "label": "Second"}
]
}
如何检索elements
列表中id
等于的值的项目pick
?
我正在尝试类似的东西:
elements[?id == pick]
但是,显然,比较器右侧的表达式是相对于我的过滤器表达式测试的对象进行评估的。
我怎样才能达到我想要的?如果这不可能开箱即用,您对我应该从哪里开始扩展 JMESPath 有什么建议吗?谢谢!
解决方案
不幸的是,JMESPath不允许引用父元素。
为了规避这个限制,在这个简单的例子中,您可以:
- 在第一个查询中读取pick属性,
- 使用刚刚读取的值创建第二个查询,
- 在第二个查询中阅读想要的内容。
实际上,多亏了f-strings,最后两个步骤可以在一条指令中执行,所以代码可以是:
pck = jmespath.search('pick', dct)
jmespath.search(f'elements[?id == `{pck}`]', dct)
其中dct是源 JSON 对象。
一个更复杂的案例
如果您有一个更复杂的案例(例如,许多这样的元素,在每种情况下具有不同的选取 值),您应该使用另一个工具。
一个非常有趣的选择是使用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经验):
- x1 , x2 , ... - 索引列 - 取自dct中的第一级键的值。
- pick - 带有(毫不奇怪)pick元素的列,
- 元素- 包含元素的列(现在每个单元格都包含整个列表)。
这个形状不是很有用,所以让我们分解 元素列:
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
要获得最终结果,您应该:
- 选择带有pick column == id的行,
- 只取元素列(连同键列,但这个细节 Pandas为您提供了开箱即用的信息)。
执行此操作的代码是:
df.query('pick == id').elements
给予:
x1 {'id': 'a', 'label': 'First_a'}
x2 {'id': 'b', 'label': 'Second_b'}
在Pandas的说法中,它是一个系列(假设是一个列表,每个元素都用索引“标记”。
现在您可以将其转换为字典或您想要的任何内容。
推荐阅读
- python - Openpyxl:将数据框添加到excel中的范围
- tensorflow - Tensorflowsharp 和 Retinanet——如何在图形运行时确定要获取的内容?
- delphi - Delphi FMX OSX 分段故障 11
- r - 如何使用 R data.table/data.frame 将长字符串拆分/解析为表格数据?
- c# - Wpf 样式 ispressed 属性不会持续
- c++ - 迭代字符串集时没有可行的转换
- javascript - 使用数组没有重复的随机非数字分配
- ios - 如何水平居中动态宽度的collectionView项目?
- swift - Siri 快捷方式:如何通过我的应用检索捐赠的 INInteraction 列表
- python - 如何从列表中删除某些值的对象?