将规则json与数据json匹配以查找python3中的值

6yoyoihd  于 2023-03-13  发布在  Python
关注(0)|答案(1)|浏览(135)

巨蟒3

需要通过对数据应用规则来查找articleid

给定一组JSON格式的规则,其中包括文章ID和相应的属性规则。
例如:rules.json

{
  "rules": [
    {
      "articleId": "art1",
      "properties_rule": [
        {
          "condition": "EQ",
          "logicalOperator": "AND",
          "propertyId": 487,
          "value": "aaaa"
        },
        {
          "condition": "EQ",
          "logicalOperator": "",
          "propertyId": 487,
          "value": "zzzz"
        }
      ],
      
    },
    {
      "articleId": "art2",
      "properties_rule": [
        {
          "condition": "GTE",
          "logicalOperator": "AND",
          "propertyId": 487,
          "value": "bbbb"
        },
        {
          "condition": "LTE",
          "logicalOperator": "",
          "propertyId": 487,
          "value": "eeee"
        }
      ],
      
    },
    {
      "articleId": "art3",
      "properties_rule": [
        {
          "condition": "GTE",
          "logicalOperator": "",
          "propertyId": 487,
          "value": "ffff"
        }
      ],
      
    }
  ]
}

Qs以及JSON格式的一组数据,其中包括某些属性的值。data.json

{
  "data": {
    "1": {
      "properties_values": [
        {
          "value": {
            "property_id": 487,
            "property_value": "aaaa",
            "response_id": 1
          }
        }
      ]
    },
    "2": {
      "properties_values": [
        {
          "value": {
            "property_id": 487,
            "property_value": "bbbb",
            "response_id": 2
          }
        }
      ]
    },
    "3": {
      "properties_values": [
        {
          "value": {
            "property_id": 487,
            "property_value": "eeee",
            "response_id": 3
          }
        }
      ]
    }
  }
}

任务是对数据应用规则并确定与规则匹配的文章ID。
如何使用提供的规则和数据JSON,根据规则JSON的“properties_rule”数组中指定的条件,确定“data”JSON中每个条目对应的“articleId”?“data”JSON中的“property_id”字段对应于“rules”JSON中的“propertyId”字段,并且“数据”JSON中的“属性值”字段对应于“规则”JSON中的“值”字段。

尝试此方法解决此问题,但不喜欢这么多for循环

要根据rules JSON的“properties_rule”数组中指定的条件确定“data”JSON中每个条目对应的“articleId”,我们可以在Python中执行以下步骤:
1.使用json模块将规则和数据JSON加载到Python字典中。
1.循环遍历“data”JSON中的每个条目。
1.对于每个条目,循环遍历“rules”JSON,根据“properties_rule”数组中指定的条件查找匹配的文章ID。
1.对于每个规则,循环遍历数据条目中的“properties_values”数组以查找匹配的属性ID。
1.如果找到匹配的属性ID,请检查属性值是否满足规则中指定的条件。如果不满足条件,请转到下一个规则。
1.如果满足所有条件,则返回与规则关联的文章ID。
1.如果找不到匹配的项目ID,则返回默认值或引发错误。
以下是实现此逻辑的示例代码:

import json

# Load the rules and data JSON files into memory
with open('rules.json', 'r') as f:
    rules_data = json.load(f)
rules = rules_data['rules']

with open('data.json', 'r') as f:
    data = json.load(f)
data = data['data']

# Loop through each rule and check if it matches the data
for rule in rules:
    properties_rule = rule['properties_rule']
    articleId = rule['articleId']
    
    # Check if all the conditions in the properties_rule array are satisfied
    matched = True
    for prop_rule in properties_rule:
        propertyId = prop_rule['propertyId']
        value = prop_rule['value']
        condition = prop_rule['condition']
        
        # Check if any of the survey responses match the condition
        response_matched = False
        for key, value_dict in data.items():
            properties_value = value_dict['properties_value']
            for prop_value in properties_value:
                survey_response = prop_value['survey_response']
                if survey_response['property_id'] == propertyId:
                    property_value = survey_response['property_value']
                    if condition == 'EQ' and property_value == value:
                        response_matched = True
                    elif condition == 'GTE' and property_value >= value:
                        response_matched = True
                    elif condition == 'LTE' and property_value <= value:
                        response_matched = True
        # If none of the survey responses match the condition, set matched to False
        if not response_matched:
            matched = False
            break
    
    # If all the conditions are satisfied, return the articleId of that rule
    if matched:
        print("Article ID: ", articleId)
        break

# If none of the rules match the data, return a default articleId
if not matched:
    print("Default Article ID")

但是寻找有效的方法。不想要那么多for循环

qyswt5oh

qyswt5oh1#

  • 寻找高效的方法,不要那么多for循环 *

您可以将每个properties_rule列表转换为函数或lambda表达式(附带一个propertyId列表以提取参数,并返回一个articleId)。

def rule_to_lambda(rule_dict):
    opRef = {'EQ': '==', 'GTE': '>=', 'LTE': '<=', 'GT': '>', 'LT': '<'}

    lStr1, lStr2, prop_ids, andOr = 'lambda ', ':', [], ''
    for ri, pr in enumerate(rule_dict['properties_rule'], 1):
        prop_ids.append(pr['propertyId'])
        prVal, lStr1 = pr['value'], f'{lStr1}{"" if ri == 1 else ", "}p{ri}'

        if ri != 1: lStr2 += f' {andOr}'
        andOr = 'or' if pr.get('logicalOperator')=='OR' else 'and'

        cond = f'{repr(prVal)} {opRef.get(pr["condition"])} p{ri}'
        lStr2 += f' (p{ri} is not None and {cond})'

    # no rules to check --> return True by default     
    if not prop_ids: lStr1, lStr2 = 'lambda *x', ': True'
 
    return rule_dict['articleId'], prop_ids, eval(lStr1+lStr2)

注意,使用eval通常是considered unsafe,但我认为在这种情况下是可以的,因为您确切地知道lStr1+lStr2中可以包含什么(pr['value']除外,但它来自解析的JSON,因此它不是表达式)。
如果用于您问题中的rules.json示例,

# import json
# with open('rules.json', 'r') as f: rules = json.load(f)

rules_list = [rule_to_lambda(r) for r in rules['rules']]

那么rules_list实际上等于

[
 ('art1', [487, 487], lambda p1, p2: (p1 is not None and 'aaaa' == p1) and (p2 is not None and 'zzzz' == p2)),
 ('art2', [487, 487], lambda p1, p2: (p1 is not None and 'bbbb' >= p1) and (p2 is not None and 'eeee' <= p2)),
 ('art3', [487], lambda p1: (p1 is not None and 'ffff' >= p1))
]

[You'仍然需要循环data中每个properties_values的每个规则,但这样您只需循环每个properties_rule字典一次,然后就可以使用创建的lambda表达式了。]
由于您需要property_value(对应于property_id)作为lambda表达式的参数,因此您可能还需要使用函数根据property_id查找data值的property_value

def get_property_value(prop_id, prop_vals:list):
    for p in prop_vals:
        if prop_id == p['value']['property_id']: 
            return p['value']['property_value']

# {k:get_property_value(487,v['properties_values']) for k,v in data['data'].items()}
# returns {'1': 'aaaa', '2': 'bbbb', '3': 'eeee'}

现在,您可以像这样循环data

# import json
# with open('rules.json', 'r') as f: rules = json.load(f)
# with open('data.json', 'r') as f: data = json.load(f)

# rules_list = [rule_to_lambda(r) for r in rules['rules']]
for k, v in data['data'].items():
    for a, prop_ids, ruleFunc in rules_list:
        pvals = v['properties_values'] 
        pvals = [get_property_value(pi, pvals) for pi in prop_ids]
        if ruleFunc(*pvals):
            print(k, ':', pvals, '---> Article ID:', a)
            break ## print only for the first rule that matches
    else: print(k, '---> Default Article ID')

对于示例data.jsonrules.json,这会在所有3行上打印 Article ID: art3,但这并不奇怪,因为art1art2规则是不可能的,除非p1p2不同[它们不可能,因为两个规则的prop_ids都是[487,487] ]。

相关问题