#python
#python
Вопрос:
У меня есть задачи, которые должны выполняться в соответствии с набором правил.
Например:
| - File2
File1 -
| - File3
Это означает, что задача File1 должна быть выполнена перед File2 и File3.
Я написал следующий код :
import json
json_string = """
{
"file1": {
"path_to_file": "file1.txt",
"children": "file2,file3"
},
"file2": {
"path_to_file": "file2.txt",
"children": ""
},
"file3": {
"path_to_file": "a/file3.txt",
"children": ""
}
"""
class Node(object):
def __init__(self, name, path_to_file=None):
self.name = name
self.path_to_file = path_to_file
self.children = []
def add_child(self, obj):
self.children.append(obj)
def dump(self):
print('%s' % (self.name))
for obj in self.children:
obj.dump()
name2info = json.loads(json_string)
def get_tree(name):
info = name2info[name]
root = Node(name, info['path_to_file'])
for child in info['children'].split(","):
if child:
root.add_child(get_tree(child))
return root
root = get_tree('file1')
root.dump()
Что дает мне:
file1
file2
file3
В этом примере print
— это execution function
в узле.
Проблема в том, что этот код не работает для случая, подобного:
File1 -
| - File3
File2 -
Если у меня есть:
json_string = """
{
"file1": {
"path_to_file": "file1.txt",
"children": "file3"
},
"file2": {
"path_to_file": "file2.txt",
"children": "file3"
},
"file3": {
"path_to_file": "a/file3.txt",
"children": ""
}
Это даст мне:
file1
file3
file2
Это должно быть:
file1
file2
file3 #3 is child of 1 and 2 - it can be executed only after 1 amp; 2 are done.
В основном каждый Узел может выполнять функцию execute (печать) только после того, как все его родители завершат свою функцию execute (печать).
Как я могу решить эту проблему?
Комментарии:
1. Можете ли вы реструктурировать свой код так, чтобы вместо ссылок от предшественника к преемнику вы меняли отношения таким образом, чтобы узлы имели ссылки на задачи, которые должны выполняться до них?
2. Итак, это не дерево, это график. Вы не можете смоделировать это с помощью дерева.
3. Просто общий комментарий: Я думаю, что было бы лучше указывать вещи в терминах «родителей» вместо «дочерних элементов». Таким образом, при добавлении новых дочерних процессов вам нужно только коснуться одной точки для нового дочернего процесса, а не касаться всех потенциальных родителей. Вероятность того, что вы забудете обновить родительский элемент, возрастает экспоненциально по мере усложнения графика зависимостей.
4. Кроме того, это довольно классическая проблема науки о данных. В зависимости от функций, которые вам нужны, рассмотрите возможность поиска уже созданной библиотеки для обработки этой конвейерной обработки за вас. Например, там, где я работаю, мы используем Luigi .
5. @Ralf Я могу заменить дочерние элементы в Json на родительские. Но как это помогает мне?
Ответ №1:
Ваше дерево зависимостей на самом деле не дерево — это DAG. Когда вы печатаете дерево по адресу file1
, file2
оно не должно быть напечатано.
Кстати, вы не должны хранить родительский файл в json, это заставит вашу систему быть деревом. (что может быть хорошо, в зависимости от ваших требований)
Комментарии:
1. В названии написано graph 🙂 Я написал это как дерево, так как я не думал о случае, который я представил в вопросе. Очевидно, что это требует изменения структуры, я просто не знаю, как создать новый тип, чтобы я мог пройти по нему в правильном порядке выполнения. Можно предположить, что существует только один корень.
2. Ваш код должен работать нормально, не могли бы вы более конкретно рассказать о проблеме?
3. Я предполагаю, что мне нужна топологическая сортировка Json, которая у меня есть
4. Ага. Вы можете использовать библиотеку. Ознакомьтесь с NetworkX: networkx.github.io
5. Я не могу найти реальный простой пример, который я мог бы преобразовать в свой случай. Эта библиотека, похоже, больше подходит для более сложных задач
Ответ №2:
Алгоритм, который вам нужен, — это «топологическая сортировка»: список L
элементов графика, такой, что если A
предшествует B
в L
, то A
не является потомком B
. Это стандартная проблема с графом; существующие библиотеки должны справиться с ней. Вот один из них.
Обратите внимание, что в общем DAG такой порядок не всегда гарантируется.
Комментарии:
1. Ключ должен быть. Я не могу найти какую-либо компактную, хорошо документированную библиотеку.
2. Я использовал неправильный термин! Это «топологическая сортировка». Я исправил комментарий и связался с библиотекой (которую я не пробовал).
3. Я это уже нашел. не обновлялся с 2016 года, и есть 0 примеров его использования
4. Слабый. Что ж, тогда, похоже, ваши варианты — самостоятельно кодировать topo sort или использовать интерфейс внешней функции.