Python рекурсивная функция для треанта js - PullRequest
0 голосов
/ 19 июня 2020

Я пытаюсь сгенерировать дерево для библиотеки treant js, однако, глядя на формат JSON, которого они ожидают, я испытываю некоторые трудности в создании дерева правильно, как они этого хотят.

В настоящее время вот что я сделал:

Это результат, который хочет библиотека :

"""
output = {
    metric_1 : {
        name : 'metric 1', desc: 'desc', contact: 'form * x - y'
    },
    children: [{
        metric_2 : {
            name : 'metric 2', desc: 'desc', contact: 'form * x - y'
        },
    },
    // Metric 2 has children, add the children attribute on the same level as metric_2
    children : [{
        ...
    }],
    {
        metric_3 : {
            name : 'metric 3', desc: 'desc', contact: 'form * x - y'
        }
    },
    ]
}
"""

Это моя попытка:

def get_records():
    # ID, Tree ID, Metric Name, Metric Description, Metric Formula, Parent, ReferenceID
    records = (('1', '1', 'metric 1', 'desc', 'form * x  - y', '', 'metric_1'),
    ('2', '1', 'metric 2', 'desc', 'form * x  - y', 'metric_1', 'metric_2'),
    ('3', '1', 'metric 3', 'desc', 'form * x  - y', 'metric_1', 'metric_3'),
    ('4', '1', 'metric 4', 'desc', 'form * x  - y', 'metric_2', 'metric_4'),
    ('5', '1', 'metric 5', 'desc', 'form * x  - y', 'metric_2', 'metric_5'))
    return records


def generate_output(record, output={}):
    def generate(record):
        #print(output)
        # rowno, tree_id, metric_name, metric_desc, metric_form, parent, refid
        try:
            output['children'].append({record[6] : {'name': record[2], 'title': record[3], 'contact': record[4]}})
        except KeyError:
            output[record[6]] = {'name': record[2], 'title': record[3], 'contact': record[4]}
        if children:=find_children(record[6]):
            try:
                if output['children']:
                    pass
            except KeyError:
                output['children'] = []
            for child in children:
                generate(child)
    generate(record)
    return output

def find_children(argrefid):
    records = get_records()
    output = []
    for record in records:
        if record[5] == argrefid:
            output.append(record)
    return output

if __name__ == '__main__':
    for record in get_records():
        print(generate_output(record))
        break 
    # Need to only pass the first element to recursively create the tree

Первый цикл работает по назначению, однако мне трудно рекурсивно создать массив children на том же уровне метри c, который они запрашивают, вот что выводит моя программа:

{'metric_1': {'name': 'metric 1', 'title': 'desc', 'contact': 'form * x  - y'}, 'children': [{'metric_2': {'name': 'metric 2', 'title': 'desc', 'contact': 'form * x  - y'}}, {'metric_4': {'name': 'metric 4', 'title': 'desc', 'contact': 'form * x  - y'}}, {'metric_5': {'name': 'metric 5', 'title': 'desc', 'contact': 'form * x  - y'}}, {'metric_3': {'name': 'metric 3', 'title': 'desc', 'contact': 'form * x  - y'}}]}

Однако я хотел бы, как я уже сказал, иметь metri c 4 и metri c 5 в качестве дочерних элементов его родителя, metric2.

Любая помощь приветствуется.

1 Ответ

1 голос
/ 19 июня 2020

Я бы не решал это рекурсивно, но итеративно:

  1. Построить элементы из каждой записи на шаге
  2. Свяжите их с соответствующими родителями на втором шаге

Пример

import json

def get_records():
           # ID, TreeID, MetricName, MetricDescription, MetricFormula, Parent, ReferenceID
    return (('1', '1', 'metric 1', 'desc', 'form * x  - y', '', 'metric_1'),
            ('2', '1', 'metric 2', 'desc', 'form * x  - y', 'metric_1', 'metric_2'),
            ('3', '1', 'metric 3', 'desc', 'form * x  - y', 'metric_1', 'metric_3'),
            ('4', '1', 'metric 4', 'desc', 'form * x  - y', 'metric_2', 'metric_4'),
            ('5', '1', 'metric 5', 'desc', 'form * x  - y', 'metric_2', 'metric_5'))

records = get_records()

# 1. build all entries and index them by their referene ID
entry_by_ref = {}
for record in records:
    entry_by_ref[record[6]] = {
        'name': record[2],
        'title': record[3],
        'contact': record[4],
    }

# 2. find root node and link all others into a tree
root = None
for record in records:
    entry = entry_by_ref.get(record[6])
    parent = entry_by_ref.get(record[5])
    if record[5] == '':
        root = entry
    elif parent is not None:
        if 'children' not in parent:
            parent['children'] = []
        parent['children'].append(entry)

print(json.dumps(root, indent=2))

вышеуказанные выходы:

{
  "name": "metric 1",
  "title": "desc",
  "contact": "form * x  - y",
  "children": [
    {
      "name": "metric 2",
      "title": "desc",
      "contact": "form * x  - y",
      "children": [
        {
          "name": "metric 4",
          "title": "desc",
          "contact": "form * x  - y"
        },
        {
          "name": "metric 5",
          "title": "desc",
          "contact": "form * x  - y"
        }
      ]
    },
    {
      "name": "metric 3",
      "title": "desc",
      "contact": "form * x  - y"
    }
  ]
}
...