簡體   English   中英

python 找到子樹的最小值和最大值

[英]python find sub tree minimum and maximum value

我有一棵帶有節點的樹,在每個節點中我都有 id、name、nodes、roles、parent_id 和 type。 我需要編寫一個 function 來檢查每個節點,如果節點有角色,那么找到最小和最大持續時間或角色進入角色。 之后我需要將它與他的父母進行比較(如果不是沒有的話),如果父母的最長持續時間比它更大,那么孩子們將獲得父母/祖父母的最長持續時間。我將添加一些示例和我的預期要得到

 # example 1
roles_1 = [{id: 'r1', 'duration': 4}]
roles_2 = [{id: 'r2', 'duration': 5}, {id: 'r3', 'duration': 8}]

input_tree1 = {
    'nodes': [
        {
            'id': '1',
            'name': 'org1',
            'parent_id': None,
            'type': 'organization',
            'nodes': [
                {
                    'id': '2',
                    'name': 'o_folder_1',
                    'org_id': '1',
                    'parent_id': '1',
                    'type': 'folder',
                    'roles': roles_1,

                    'nodes': [
                        {
                            'id': '3',
                            'name': 'o1_f1_project_1',
                            'nodes': [],
                            'org_id': '1',
                            'parent_id': '2',
                            'type': 'project',
                            'roles': roles_2,
                        }
                    ],
                }
            ],
        }
    ]
}

我有一個角色列表,每個角色列表都包含 object 的角色。 每個角色都有 id 和 duration。 在這個例子中,我的父org1有一個孩子o_folder_1和一個孫子o1_f1_project_1 ,我需要做的是檢查孫子是否有角色,如果是,我計算子樹的最小和最大持續時間,這里是 8 ,然后 go 升級計算角色,如果節點有,這里是 4.. 4 小於 8 所以我需要添加一個更新一個 max_duration 和 minimum_duration 的新字段,正如您在預期樹中看到的那樣:

  expected_tree1 = {'nodes': [
    {
        'id': '1',
        'name': 'org1',
        'parent_id': None,
        'type': 'organization',
        'nodes': [
            {
                'id': '2',
                'name': 'o_folder_1',
                'org_id': '1',
                'parent_id': '1',
                'type': 'folder',
                'roles': roles_1,
                'min_duration': 4,
                'max_duration': 4,
                'nodes': [
                    {
                        'id': '3',
                        'name': 'o1_f1_project_1',
                        'nodes': [],
                        'org_id': '1',
                        'parent_id': '2',
                        'type': 'project',
                        'roles': roles_2,
                        'min_duration': 4,
                        'max_duration': 8
                    }
                ],

            }
        ],
    }
]
}

正如您在此處看到的,我為每個具有正確值的節點添加了 min_duration 和 maximum_duration 的新字段。 示例 2:

  # example 2
roles_1 = [{id: 'r1', 'duration': 12}]
roles_2 = [{id: 'r2', 'duration': 4}, {id: 'r3', 'duration': 2}]
roles_3 = [{id: 'r4', 'duration': 5}]
roles_4 = [{id: 'r5', 'duration': 9}]

input_tree2 = {'nodes':
    [
        {
            'id': '1',
            'name': 'org1',
            'parent_id': None,
            'type': 'organization',
            'nodes':
                [
                    {
                        'id': '2',
                        'name': 'o1_folder_1',
                        'org_id': '1',
                        'parent_id': '1',
                        'type': 'folder',
                        'roles': roles_1,
                        'min_duration': 12,
                        'max_duration': 12
                        'nodes': [
                            {
                                'id': '3',
                                'name': 'o1_f1_project_1',
                                'nodes': [],
                                'org_id': '1',
                                'parent_id': '2',
                                'type': 'project',
                                'roles': roles_2,

                            },
                            {
                                'id': '4',
                                'name': 'o1_f1_project_2',
                                'nodes': [],
                                'org_id': '1',
                                'parent_id': '2',
                                'type': 'project',
                                'roles': roles_3,

                            },

                        ],
                    },

                    {
                        'id': '4',
                        'name': 'o1_folder_2',
                        'org_id': '1',
                        'parent_id': '1',
                        'type': 'folder',
                        'roles': roles_4,
                        'nodes': [
                            {
                                'id': '3',
                                'name': 'o1_f2_project1',
                                'nodes': [],
                                'org_id': '1',
                                'parent_id': '4',
                                'type': 'project',
                                'roles': roles_3,
                            }
                        ],
                    },

                ],
        }]}

預期樹 2

  expected_tree2 = {'nodes':
    [
        {
            'id': '1',
            'name': 'org1',
            'parent_id': None,
            'type': 'organization',
            'nodes':
                [
                    {
                        'id': '2',
                        'name': 'o1_folder_1',
                        'org_id': '1',
                        'parent_id': '1',
                        'type': 'folder',
                        'roles': roles_1,
                        'min_duration': 12,
                        'max_duration': 12
                        'nodes': [
                            {
                                'id': '3',
                                'name': 'o1_f1_project_1',
                                'nodes': [],
                                'org_id': '1',
                                'parent_id': '2',
                                'type': 'project',
                                'roles': roles_2,
                                'min_duration': 2,
                                'max_duration': 12
                            },
                            {
                                'id': '4',
                                'name': 'o1_f1_project_2',
                                'nodes': [],
                                'org_id': '1',
                                'parent_id': '2',
                                'type': 'project',
                                'roles': roles_2,
                                'min_duration': 5,
                                'max_duration': 12
                            },
                        ],
                    },

                    {
                        'id': '4',
                        'name': 'o1_folder_2',
                        'org_id': '1',
                        'parent_id': '1',
                        'type': 'folder',
                        'roles': roles_4,
                        'min_duration': 9,
                        'max_duration': 9
                        'nodes': [
                            {
                                'id': '3',
                                'name': 'o1_f2_project1',
                                'nodes': [],
                                'org_id': '1',
                                'parent_id': '4',
                                'type': 'project',
                                'roles': roles_3,
                                'min_duration': 5,
                                'max_duration': 9
                            }
                        ],
                    },

                ],
        }]}

示例 3

 roles_1 = [{id: 'r1', 'duration': 18}]
roles_2 = [{id: 'r2', 'duration': 4}, {id: 'r3', 'duration': 2}]
roles_3 = [{id: 'r4', 'duration': 5}]
roles_4 = [{id: 'r5', 'duration': 9}, {id: 'r5', 'duration': 12}]
roles_5 = [{id: 'r6', 'duration': 20}]
input_tree3 = {'nodes':
    [
        {
            'id': '1',
            'name': 'org1',
            'parent_id': None,
            'type': 'organization',
            'roles': roles_1,
            'nodes':
                [
                    {
                        'id': '2',
                        'name': 'o1_folder_1',
                        'org_id': '1',
                        'parent_id': '1',
                        'type': 'folder',
                        'roles': roles_3,
                        'min_duration': 12,
                        'max_duration': 12,
                        'nodes': [
                            {
                                'id': '3',
                                'name': 'o1_f1_project_1',
                                'nodes': [],
                                'org_id': '1',
                                'parent_id': '2',
                                'type': 'project',
                                'roles': roles_2,

                            },
                            {
                                'id': '4',
                                'name': 'o1_f1_project_2',
                                'nodes': [],
                                'org_id': '1',
                                'parent_id': '2',
                                'type': 'project',
                                'roles': roles_2,

                            },

                        ],

                    },

                    {
                        'id': '4',
                        'name': 'o1_folder_2',
                        'org_id': '1',
                        'parent_id': '1',
                        'type': 'folder',
                        'roles': roles_5,
                        'nodes': [
                            {
                                'id': '3',
                                'name': 'o1_f2_project1',
                                'nodes': [],
                                'org_id': '1',
                                'parent_id': '2',
                                'type': 'project',
                                'roles': roles_4,

                            }
                        ],

                    },

                ],
        }]}

預期樹 3

 expected_tree3 = {'nodes':
    [
        {
            'id': '1',
            'name': 'org1',
            'parent_id': None,
            'type': 'organization',
            'roles': roles_1,
            'min_duration': 18,
            'max_duration': 18,
            'nodes':
                [
                    {
                        'id': '2',
                        'name': 'o1_folder_1',
                        'org_id': '1',
                        'parent_id': '1',
                        'type': 'folder',
                        'roles': roles_3,
                        'min_duration': 5,
                        'max_duration': 18,
                        'nodes': [
                            {
                                'id': '3',
                                'name': 'o1_f1_project_1',
                                'nodes': [],
                                'org_id': '1',
                                'parent_id': '2',
                                'type': 'project',
                                'roles': roles_2,
                                'min_duration': 2,
                                'max_duration': 18

                            },
                            {
                                'id': '4',
                                'name': 'o1_f1_project_2',
                                'nodes': [],
                                'org_id': '1',
                                'parent_id': '2',
                                'type': 'project',
                                'roles': roles_2,
                                'min_duration': 2,
                                'max_duration': 18

                            },
                        ],

                    },

                    {
                        'id': '4',
                        'name': 'o1_folder_2',
                        'org_id': '1',
                        'parent_id': '1',
                        'type': 'folder',
                        'roles': roles_5,
                        'min_duration': 18,
                        'max_duration': 20,
                        'nodes': [
                            {
                                'id': '3',
                                'name': 'o1_f2_project1',
                                'nodes': [],
                                'org_id': '1',
                                'parent_id': '4',
                                'type': 'project',
                                'roles': roles_4,
                                'min_duration': 9,
                                'max_duration': 20

                            }
                        ],
                    },

                ],

        }]}

正如您在示例中看到的那樣,每次我檢查最后一個孩子是否有角色時,如果他有,它會計算最大持續時間,然后與他的父母進行比較,如果他有,如果父母有最大持續時間,它將得到它..但如果沒有,孩子只有孩子保持最長持續時間,他的父母不會受id影響,也不會得到孩子的持續時間..

假設:

  • 當 parent_id 為 None 時為根
  • 它可以有多個級別(根->子->孫->....)
  • 如果根沒有角色,請檢查他的孩子。
  • 根可以是一些孩子(不總是二叉樹)

實際上我試圖做的

def add_min_max_duration(tree:Dict):

for node in tree["nodes"]:
    if "roles" in node.keys():
        node["min_duration"] = 25
        node["max_duration"] = 0
        for role in node["roles"]:
            node["min_duration"] = min(node["min_duration"], role.duration)
            node["max_duration"] = max(node["max_duration"], role.duration)
    add_min_max_duration(node)

但這不好,因為它不能與他的父母/祖父母相比。

min_max數據類型開始,使用+操作組合兩個min_max實例 -

mm1 = min_max(2,5)
mm2 = min_max(3,9)
mm3 = mm1 + mm2    # (2, 9)

我們可以這樣寫——

from math import inf

class min_max:
  def __init__(self, min = +inf, max = -inf):
    self.min = min
    self.max = max
  def __add__(self, other):
    return min_max(min(self.min, other.min), max(self.max, other.max))

我們可以通過編寫 role_min_max 來計算角色的role_min_max -

def role_min_max(role):
  return iter_min_max(x["duration"] for x in role)
  
def iter_min_max(iterable):
  r = min_max()
  for value in iterable:
    r = r + min_max(value, value)
  return r

最后, tree_min_max(-Infinity, Infinity)的默認 min_max 開始,如果存在,我們將其+tree["roles"]值的role_min_max 對於子tree["nodes"]的所有node ,我們使用更新后的 min_max, mm調用tree_min_max(node, mm) -

def tree_min_max(tree, mm = min_max()):
  if "roles" in tree:
    mm = mm + role_min_max(tree["roles"])
  return {
    "duration_min": mm.min,
    "duration_max": mm.max,
    **tree,
    "nodes": list(tree_min_max(node, mm) for node in tree["nodes"])
  }

我們將使用json漂亮地打印新創建的樹 -

import json
print(json.dumps(tree_min_max(input_tree3), indent=2))
{
  "duration_min": Infinity,
  "duration_max": -Infinity,
  "nodes": [
    {
      "duration_min": 18,
      "duration_max": 18,
      "id": "1",
      "name": "org1",
      "parent_id": null,
      "type": "organization",
      "roles": [
        {
          "id": "r1",
          "duration": 18
        }
      ],
      "nodes": [
        {
          "duration_min": 5,
          "duration_max": 18,
          "id": "2",
          "name": "o1_folder_1",
          "org_id": "1",
          "parent_id": "1",
          "type": "folder",
          "roles": [
            {
              "id": "r4",
              "duration": 5
            }
          ],
          "nodes": [
            {
              "duration_min": 2,
              "duration_max": 18,
              "id": "3",
              "name": "o1_f1_project_1",
              "nodes": [],
              "org_id": "1",
              "parent_id": "2",
              "type": "project",
              "roles": [
                {
                  "id": "r2",
                  "duration": 4
                },
                {
                  "id": "r3",
                  "duration": 2
                }
              ]
            },
            {
              "duration_min": 2,
              "duration_max": 18,
              "id": "4",
              "name": "o1_f1_project_2",
              "nodes": [],
              "org_id": "1",
              "parent_id": "2",
              "type": "project",
              "roles": [
                {
                  "id": "r2",
                  "duration": 4
                },
                {
                  "id": "r3",
                  "duration": 2
                }
              ]
            }
          ]
        },
        {
          "duration_min": 18,
          "duration_max": 20,
          "id": "4",
          "name": "o1_folder_2",
          "org_id": "1",
          "parent_id": "1",
          "type": "folder",
          "roles": [
            {
              "id": "r6",
              "duration": 20
            }
          ],
          "nodes": [
            {
              "duration_min": 9,
              "duration_max": 20,
              "id": "3",
              "name": "o1_f2_project1",
              "nodes": [],
              "org_id": "1",
              "parent_id": "2",
              "type": "project",
              "roles": [
                {
                  "id": "r5",
                  "duration": 9
                },
                {
                  "id": "r5",
                  "duration": 12
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

請注意,您的role_*數據應將id放在引號中,否則字典的鍵實際上是id function,而不是您可能想要的字符串"id"

另請注意,提供的輸入中有一個硬代碼"min_duration""max_duration" ,我在這篇文章中將其刪除。

要從根音符中刪除duration_minduration_max ,我們可以添加一個特殊情況,用於節點中不存在"roles"時 -

def tree_min_max(tree, mm = min_max()):
  if "roles" in tree:
    mm = mm + role_min_max(tree["roles"])
    return {
      "duration_min": mm.min,
      "duration_max": mm.max,
      **tree,
      "nodes": list(tree_min_max(node, mm) for node in tree["nodes"])
    }
  else:
    return {
      **tree,
      "nodes": list(tree_min_max(node, mm) for node in tree["nodes"])
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM