from functools import reduce as _reduce
class CircularDependencyError(ValueError):
def __init__(self, data):
s = "Circular dependencies exist among these items: {{{}}}".format(
", ".join(
"{!r}:{!r}".format(key, value) for key, value in sorted(data.items())
)
)
super(CircularDependencyError, self).__init__(s)
self.data = data
def toposort(data):
if len(data) == 0:
return
# Copy the input so as to leave it unmodified.
data = data.copy()
# Ignore self dependencies.
for k, v in data.items():
v.discard(k)
# Find all items that don't depend on anything.
extra_items_in_deps = _reduce(set.union, data.values()) - set(data.keys())
# Add empty dependences where needed.
data.update({item: set() for item in extra_items_in_deps})
while True:
ordered = set(item for item, dep in data.items() if len(dep) == 0)
if not ordered:
break
yield ordered
data = {
item: (dep - ordered) for item, dep in data.items() if item not in ordered
}
if len(data) != 0:
raise CircularDependencyError(data)
if __name__ == "__main__":
group1 = {"A": {"B", "E"}, "C": {"B"}, "B": {"E", "F"}, "G": {"B"}}
print(list(toposort(group1)))
group2 = {"X": {"Y"}, "Z": {"Y"}}
print(list(toposort(group2)))
# 如果一开始给的数据, 是group1和2合并在一起的
# 如何把数据分成两个组, 并且分别做拓扑排序
init_data = {**group1, **group2}
print(list(toposort(init_data)))