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

时间:2020-01-13 10:31:50

标签: python pandas jmespath

具有如下对象:

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

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

我正在尝试类似的事情:

elements[?id == pick]

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

如何实现我想要的?如果无法立即使用,您对我应该在哪里扩展JMESPath提出任何建议?谢谢!

1 个答案:

答案 0 :(得分:2)

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

要避免这种限制,在这种简单情况下,您可以:

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

实际上,多亏了 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 的经验):

  • x1 x2 ,...-索引列-从第一级键获取的值 在 dct 中。
  • pick -具有(不出意外的) pick 元素的列,
  • elements -具有 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

要获得最终结果,您应该:

  • 选择带有 pick 列== id
  • 的行
  • 仅使用 elements 列(与键列一起使用,但是此详细信息 Pandas 为您提供了开箱即用的功能。

执行此操作的代码是:

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

给予:

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

Pandas 中,它是一个 Series (假设每个元素都有一个列表 带有索引的“标签”。

现在您可以将其隐藏到字典或任何您想要的东西上。

相关问题