【问题标题】:Filtering Json array (with no root node name) based on nested multiple conditions in python基于python中嵌套的多个条件过滤Json数组(没有根节点名称)
【发布时间】:2021-09-21 02:43:12
【问题描述】:

我正在尝试根据多个条件使用 Python 过滤 Json 数组。我的 Json 与此类似(无根名称):

     {           
       "id": "123455",           
       "outter": {
          "inner": [
            {
              "nox": "abc:6666",
              "code": "1329",        
            }
           ],    
        },
        "topic": {
         "reference": "excel"
        }, 
        "date1": "1990-07-28T03:52:44-04:00",
        "finalDate": "1990-07-28T03:52:44-04:00"
      }
      {           
       "id": "123435",           
       "outter": {
          "inner": [
            {
              "nox": "abc:6666",
              "code": "9351",        
            }
           ],    
        },
        "topic": {
         "reference": "excel"
        }, 
        "date1": "1990-07-28T03:52:44-04:00",
        "finalDate": "1995-07-28T03:52:44-04:00"
      }

我的目标是根据 2 个条件进行过滤并返回所有匹配的条件。

1: 外部 --> 内部 --> 代码 = 9351 AND

2:最终日期 >= 1995

到目前为止,我可以使用以下代码单独执行此检查:

   data = pd.read_json('myFile.ndjson', lines = True)

   for item in data['outter']:
      for x in item['inner']:
         if(x['code'] == '9351'):
            found....

但不确定如何同时执行这两项操作,因为我必须使用data['outter']data['finalDate'] 启动循环,并且在循环内我只能看到数组的那个元素,而不是完整的数组。

感谢任何帮助,谢谢!

【问题讨论】:

  • 你有一个小错字 - 因为它看起来像你有一个 json 数组,你可以用大括号 [] 包装输入 json 并用逗号分隔元素。巧合的是,这被用作 Python list 对象。

标签: arrays json python-3.x


【解决方案1】:

这是一种可以如上所述过滤列表的解决方案。我使用的是列表推导而不是循环,其中可能有一些可以改进的东西,但结果似乎至少符合预期。

注意:这使用了 Python 3.8 中引入的 walrus := 运算符。如果您运行的是较早的 Python 版本,您可能可以删除使用它的代码,但在这种情况下我并没有过多打扰。

from pprint import pprint


data_list = [
    {
        "id": "123455",
        "outter": {
            "inner": [
                {
                    "nox": "abc:6666",
                    "code": "1329",
                }
            ],
        },
        "topic": {
            "reference": "excel"
        },
        "date1": "1990-07-28T03:52:44-04:00",
        "finalDate": "1990-07-28T03:52:44-04:00"
    },
    {
        "id": "123435",
        "outter": {
            "inner": [
                {
                    "nox": "abc:6666",
                    "code": "9351",
                }
            ],
        },
        "topic": {
            "reference": "excel"
        },
        "date1": "1990-07-28T03:52:44-04:00",
        "finalDate": "1995-07-28T03:52:44-04:00"
    }
]

result = [d for d in data_list
          if (year := d['finalDate'][:4]).isnumeric() and year >= '1995'
          and any(str(inner['code']) == '9351'
                  for inner in d['outter']['inner'] or [])]

pprint(result)

@ted 提出了一个很好的观点,即可读性很重要,所以我有时间回过头来以典型的循环格式编写它(基本上与上面的逻辑相同)。我还有很多 cmets 希望澄清代码中发生的事情,希望对您有所帮助:-)

from pprint import pprint
from typing import Dict, List

result = []

# Looping over each dictionary in list
for d in data_list:
    # Grab the year part, first four characters of `finalDate`
    year = d['finalDate'][:4]
    # isnumeric() to confirm the year part is an an integer
    # then check if string (now confirmed to be numeric) has a higher
    # ASCII value than 1995.
    valid_year = year.isnumeric() and year >= '1995'
    # Simple, if it doesn't match our desired year then continue
    # with next loop iteration
    if not valid_year:
        continue
    # Get inner list, then loop over it
    inner_list: List[Dict] = d['outter']['inner']
    for inner in inner_list:
        if inner['code'] == '9351':
            # We found an inner with our desired code!
            break
    # The for-else syntax is pretty self-explanatory. This `else` statement is
    # only run when we don't `break` out of the loop above.
    else:
        # No break statement was run, so the desired code did not match
        # any elements. Again, continue with the next iteration.
        continue
    # At this point, we know it's valid since it matched both our
    # conditions, so we add it to the result list.
    result.append(d)

# Print the result, but it should be the same
pprint(result)

【讨论】:

  • 虽然这可能会解决问题,但我相信具有多个内联条件和海象运算符的精美单行理解列表对于提出问题的人来说可能不是一个非常明确的解决方案来理解和改进。 “美胜于丑。显式胜于隐式。简单胜于复杂。复杂胜于复杂。扁平胜于嵌套。稀疏胜于密集。可读性很重要。”
  • 是的,重点。虽然我确实尝试将它分成多行以提高可读性,所以没有一行太长,事后看来,使用列表推导和海象运算符来尽快解决问题 - 可能 not 是最清楚的整体解决方案。
  • @ted 我确实更新了我的答案,以提供适用于
  • @rv.kvetch,在执行您的代码时,我得到以下信息: 'TypeError: string indices must be integers' for line --> year = d['recordedDate'][:4] ...在这种情况下,d 仅重新调整节点名称 id、outter、inner、topic、date1、finalDate ...可能缺少什么?
  • @rv.kvetch,是的,它是一个 json 字符串。我按照您的建议使用了 json.load 并按预期工作。谢谢!!!
【解决方案2】:

试试这样的..根据您的需要更改过滤器:)

for item in data:
    if item['finalDate'].startswith("1995"):
        for inner in item['outter']['inner']:
            if inner['code'] == '9351':
                print(item)

【讨论】:

  • 这仅适用于年份为 1995 的 finalDate :-)
猜你喜欢
  • 2020-07-04
  • 2021-08-04
  • 2021-09-25
  • 1970-01-01
  • 2022-08-03
  • 2019-09-10
  • 2019-12-16
  • 1970-01-01
  • 2021-09-17
相关资源
最近更新 更多