如何将对象列表转换为对象层次结构?

问题描述 投票:0回答:1

我有包含此表的 SQLlite 数据库: 在此表中,我们可以看到描述特定任务的行。任务的嵌套是使用 root_task_id 单元实现的。例如: id:1 的任务是 id:19 的任务的根任务,id:19 的任务是 id:20 的任务的根任务。这意味着: 的任务id:20是id:19的任务的子任务,id:19的任务是id:1的任务的子任务。 当我从数据库获取这些数据到 Python 程序时,我想通过使用 Task 类的对象来创建此任务的层次结构:

class Task:
     def __init__(self, task_id, root_task_id, task_name, task_text, task_is_executed, subtasks = []):
        self.id = task_id
        self.root_task_id = root_task_id
        self.name = task_name
        self.text = task_text
        if task_is_executed == 0:
            self.is_executed = "No executed"
        else:
            self.is_executed = "EXECUTED"
        self.subtasks = subtasks

此任务的层次结构必须使用 Task 类对象的 subtasks 属性来实现。简而言之,我需要根据 SQL 表的 root_task_id 单元实现的层次结构将任务打包为子任务。

我写了这段代码,但是有一些错误,我无法检测到:

def wrap_up_task_recursive(task: Task, tasks: list[Task], depth = 0):
    for root_task in tasks:
        print(f"root_task with id: {root_task.id}, is root? for task with id: {task.id}, that has root task with id: {task.root_task_id}?")
        print(depth)
        if task.root_task_id == root_task.id:
            print("Yes")
            root_task.subtasks.append(task)
            break
        else:
            if len(root_task.subtasks) != 0:
                wrap_up_task_recursive(task=task, tasks=root_task.subtasks, depth=depth + 1)


def convertTasksToUserFrandlyFormat2(all_tasks: list[Task]) -> list[Task]:
    root_tasks: list[Task] = []
    root_tasks_indexes: list[int] = []
    for index, task in enumerate(all_tasks):
        if task.root_task_id == None:
            root_tasks.append(task)
            root_tasks_indexes.append(index)
    root_tasks_indexes.sort(reverse=True)
    print(f"Root tasks indexes: {root_tasks_indexes}")
    for index in root_tasks_indexes:
        all_tasks.pop(index)
    print(f"**********root_tasks**********")
    for rt in root_tasks:
        print(f"id: {rt.id}")
        print(f"root_id: {rt.root_task_id}")
        print(f"sub: {len(rt.subtasks)}")
    print(f"**********Subtasks**********")
    for t in all_tasks:
        print(f"id: {t.id}")
        print(f"root_id: {t.root_task_id}")
        print(f"sub: {len(rt.subtasks)}")
    
    for task in all_tasks:
        wrap_up_task_recursive(task=task, tasks=root_tasks)
    return root_tasks

def indentation(depth: int) -> str:
    resultStr = ""
    for _ in range(depth):
        resultStr += "  "
    return resultStr

def recursiveReading(task: Task, depth = 0):
    print(f"{indentation(depth)} id = {task.id}")
    print(task.subtasks)
    print(len(task.subtasks))

def readTasksToUserFrandlyFormat(all_tasks: list[Task]):
    for task in all_tasks:
        recursiveReading(task)


task1 = Task(task_id=1, root_task_id=None, task_name="New task", task_text="This is new task", task_is_executed=0)
task2 = Task(task_id=14, root_task_id=None, task_name="New task", task_text="This is new task", task_is_executed=0)
task3 = Task(task_id=15, root_task_id=None, task_name="New task", task_text="This is new task", task_is_executed=0)
task4 = Task(task_id=16, root_task_id=None, task_name="New task", task_text="This is new task", task_is_executed=0)
task5 = Task(task_id=17, root_task_id=None, task_name="New task", task_text="This is new task", task_is_executed=0)
task6 = Task(task_id=18, root_task_id=None, task_name="New task", task_text="This is new task", task_is_executed=0)
task7 = Task(task_id=19, root_task_id=1, task_name="New task", task_text="This is new task", task_is_executed=0)
task8 = Task(task_id=20, root_task_id=19, task_name="New task", task_text="This is new task", task_is_executed=0)
all_tasks = [task1, task2, task3, task4, task5, task6, task7, task8]
h_all_tasks = convertTasksToUserFrandlyFormat2(all_tasks)
readTasksToUserFrandlyFormat(h_all_tasks)

控制台输出:

Root tasks indexes: [5, 4, 3, 2, 1, 0]
**********root_tasks**********
id: 1
root_id: None
sub: 0
id: 14
root_id: None
sub: 0
id: 15
root_id: None
sub: 0
id: 16
root_id: None
sub: 0
id: 17
root_id: None
sub: 0
id: 18
root_id: None
sub: 0
**********Subtasks**********
id: 19
root_id: 1
sub: 0
id: 20
root_id: 19
sub: 0
root_task with id: 1, is root? for task with id: 19, that has root task with id: 1?
0
Yes
root_task with id: 1, is root? for task with id: 20, that has root task with id: 19?
0
root_task with id: 19, is root? for task with id: 20, that has root task with id: 19?
1
Yes
root_task with id: 14, is root? for task with id: 20, that has root task with id: 19?
0
root_task with id: 19, is root? for task with id: 20, that has root task with id: 19?
1
Yes
root_task with id: 15, is root? for task with id: 20, that has root task with id: 19?
0
root_task with id: 19, is root? for task with id: 20, that has root task with id: 19?
1
Yes
root_task with id: 16, is root? for task with id: 20, that has root task with id: 19?
0
root_task with id: 19, is root? for task with id: 20, that has root task with id: 19?
1
Yes
root_task with id: 17, is root? for task with id: 20, that has root task with id: 19?
0
root_task with id: 19, is root? for task with id: 20, that has root task with id: 19?
1
Yes
root_task with id: 18, is root? for task with id: 20, that has root task with id: 19?
0
root_task with id: 19, is root? for task with id: 20, that has root task with id: 19?
1
Yes
 id = 1
[<myTaskManager.Task object at 0x000001BCA396E750>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>]
7
 id = 14
[<myTaskManager.Task object at 0x000001BCA396E750>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>]
7
 id = 15
[<myTaskManager.Task object at 0x000001BCA396E750>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>]
7
 id = 16
[<myTaskManager.Task object at 0x000001BCA396E750>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>]
7
 id = 17
[<myTaskManager.Task object at 0x000001BCA396E750>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>]
7
 id = 18
[<myTaskManager.Task object at 0x000001BCA396E750>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>]
7
python recursion hierarchy
1个回答
0
投票

令人惊讶的是,我的所有代码都工作正常,除了以下行:

def __init__(self, task_id, root_task_id, task_name, task_text, task_is_executed, subtasks = []):

在这行代码中,我有一个带有默认参数的构造函数:subtasks = [],这导致了Task类的所有对象都具有相同的子任务列表(引用相同的内存单元)的问题。当您使用“可变”对象作为默认值时,是什么导致了混乱;原因很简单:构造函数在每次调用中都使用相同的“默认参数”对象。任何想要更详细地了解它的人,我强烈建议阅读这篇post,@Michael Butscher 在评论中建议了我。 我需要做什么才能让我的代码按预期工作?为此,您只需更改两行代码:将构造函数中的 subtasks = [] 默认参数替换为

subtasks = None

,然后将 self.subtasks = subtasks 替换为 self.subtasks = [] init函数。事情应该是这样的: class Task: def __init__(self, task_id, root_task_id, task_name, task_text, task_is_executed, subtasks = None): self.id = task_id self.root_task_id = root_task_id self.name = task_name self.text = task_text if task_is_executed == 0: self.is_executed = "No executed" else: self.is_executed = "EXECUTED" if subtasks == None: self.subtasks = [] else: self.subtasks = subtasks 我还根据 SQL 表的

root_task_id
 单元实现的层次结构附加了包 
tasks

作为 subtasks 的完整代码: class Task: def __init__(self, task_id, root_task_id, task_name, task_text, task_is_executed, subtasks = None): self.id = task_id self.root_task_id = root_task_id self.name = task_name self.text = task_text if task_is_executed == 0: self.is_executed = "No executed" else: self.is_executed = "EXECUTED" if subtasks == None: self.subtasks = [] else: self.subtasks = subtasks def wrap_up_task_recursive(task: Task, tasks: list[Task], depth = 0): for root_task in tasks: print(f"root_task with id: {root_task.id}, is root? for task with id: {task.id}, that has root task with id: {task.root_task_id}?") print(depth) if task.root_task_id == root_task.id: print("Yes") root_task.subtasks.append(task) break else: if len(root_task.subtasks) != 0: wrap_up_task_recursive(task=task, tasks=root_task.subtasks, depth=depth + 1) def convertTasksToUserFrandlyFormat2(all_tasks: list[Task]) -> list[Task]: root_tasks: list[Task] = [] root_tasks_indexes: list[int] = [] for index, task in enumerate(all_tasks): if task.root_task_id == None: root_tasks.append(task) root_tasks_indexes.append(index) root_tasks_indexes.sort(reverse=True) print(f"Root tasks indexes: {root_tasks_indexes}") for index in root_tasks_indexes: all_tasks.pop(index) print(f"**********root_tasks**********") for rt in root_tasks: print(f"id: {rt.id}") print(f"root_id: {rt.root_task_id}") print(f"sub: {len(rt.subtasks)}") print(f"**********Subtasks**********") for t in all_tasks: print(f"id: {t.id}") print(f"root_id: {t.root_task_id}") print(f"sub: {len(rt.subtasks)}") for task in all_tasks: wrap_up_task_recursive(task=task, tasks=root_tasks) return root_tasks def indentation(depth: int) -> str: resultStr = "" for _ in range(depth): resultStr += "|__" return resultStr def recursiveReading(task: Task, depth = 0): print(f"{indentation(depth)} id = {task.id}") if len(task.subtasks) != 0: for subtask in task.subtasks: recursiveReading(subtask, depth + 1) def readTasksToUserFrandlyFormat(all_tasks: list[Task]): print("********Task hierarchy********") for task in all_tasks: recursiveReading(task) task1 = Task(task_id=1, root_task_id=None, task_name="New Task", task_text="This is new task", task_is_executed=0) task2 = Task(task_id=2, root_task_id=1, task_name="New Task", task_text="This is new task", task_is_executed=0) task3 = Task(task_id=3, root_task_id=None, task_name="New Task", task_text="This is new task", task_is_executed=0) task4 = Task(task_id=4, root_task_id=2, task_name="New Task", task_text="This is new task", task_is_executed=0) task5 = Task(task_id=5, root_task_id=4, task_name="New Task", task_text="This is new task", task_is_executed=0) listOfTasks = [task1, task2, task3, task4, task5] listOfTasksWithHierarchy = convertTasksToUserFrandlyFormat2(listOfTasks) # Here list of packed tasks as subtasks according to hierarchy implemented by root_task_id cells of SQL table. readTasksToUserFrandlyFormat(listOfTasksWithHierarchy) 控制台输出:

Root tasks indexes: [2, 0]
**********root_tasks**********
id: 1
root_id: None
sub: 0
id: 3
root_id: None
sub: 0
**********Subtasks**********
id: 2
root_id: 1
sub: 0
id: 4
root_id: 2
sub: 0
id: 5
root_id: 4
sub: 0
root_task with id: 1, is root? for task with id: 2, that has root task with id: 1?
0
Yes
root_task with id: 1, is root? for task with id: 4, that has root task with id: 2?
0
root_task with id: 2, is root? for task with id: 4, that has root task with id: 2?
1
Yes
root_task with id: 3, is root? for task with id: 4, that has root task with id: 2?
0
root_task with id: 1, is root? for task with id: 5, that has root task with id: 4?
0
root_task with id: 2, is root? for task with id: 5, that has root task with id: 4?
1
root_task with id: 4, is root? for task with id: 5, that has root task with id: 4?
2
Yes
root_task with id: 3, is root? for task with id: 5, that has root task with id: 4?
0
********Task hierarchy********
 id = 1
|__ id = 2
|__|__ id = 4
|__|__|__ id = 5
 id = 3

© www.soinside.com 2019 - 2024. All rights reserved.