个性化阅读
专注于IT技术分析

使用JMESPath根据另一个查询结果过滤列表

具有以下对象:

{
  "pick": "a", "elements": [
    {"id": "a", "label": "First"}, {"id": "b", "label": "Second"}
  ]
}

如何在id等于pick值的元素列表中检索该项目?

我正在尝试类似的东西:

elements[?id == pick]

但是, 显然, 比较器右侧的表达式是根据我的过滤器表达式相对于要测试的对象进行评估的。

我怎样才能实现自己想要的?如果这不可能, 你是否对我应该在哪里扩展JMESPath有任何建议?谢谢!


#1


不幸的是, JMESPath不允许引用父元素。

为了避免这种限制, 在这种简单情况下, 你可以:

  • 在第一个查询中读取pick属性,
  • 使用刚刚读取的值创建第二个查询,
  • 在第二个查询中读取所需的内容。

实际上, 由于有了f字符串, 可以在一条指令中执行最后两个步骤, 因此代码可以是:

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', ...

说明(如果你没有熊猫经验):

  • x1, x2, …-索引列-从ctt中的第一级键获取的值。
  • 选择-具有(不奇怪)选择元素的列,
  • elements-具有元素的列(目前, 每个单元格都包含整个列表)。

这个形状不是很有用, 所以让我们爆炸元素列:

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

为了获得最终结果, 你应该:

  • 选择带有选择列== id的行,
  • 仅包含元素列(与关键列一起使用, 但是Pandas的详细信息为你提供了开箱即用的功能)。

要做的代码是:

df.query('pick == id').elements

给予:

x1     {'id': 'a', 'label': 'First_a'}
x2    {'id': 'b', 'label': 'Second_b'}

在Pandas的说法中, 它是一个Series(比方说, 一个列表, 每个元素都”标记”有一个索引)。

现在, 你可以将其隐藏到词典或任何你想要的东西中。

赞(0)
未经允许不得转载:srcmini » 使用JMESPath根据另一个查询结果过滤列表

评论 抢沙发

评论前必须登录!