我有一个像Foo这样的类,它有一个“depends_on”属性,它是一个其他Foo
个实例的数组。我希望能够得到一个Foos列表并对它们进行排序,使得依赖于另一个foo的foo大于它。例如,如果foo b
依赖于foo a
,则数组应该是[a,b]
的顺序。我认为最好给每个foo一个order
字段并对该字段进行排序,而不是使用__lt__
。
class Foo(object):
def __init__(self, name, depends_on=[]):
self.order = 0
self.name = name
self.depends_on = depends_on
a = Foo('a')
b = Foo('b', [a])
c = Foo('c', [b])
d = Foo('d')
e = Foo('e')
f = Foo('f', [e])
g = Foo('g', [f, b])
foos = [a,b,c,d,e,f,g]
我已经制作了一个类似于此的递归函数,它似乎有效,但我认为有更好的方法。
在第一遍中,我将数组中的每个对象相互比较。如果对象x依赖于对象y,我将对象x的order
字段递增1。
在第二遍中,我只比较大于或等于1的order
的foos;即依赖至少另一个foo的foos。同样,如果它们相互依赖,我会增加这个foos子集的order
字段。
我继续这种模式,直到不再进行比较为止。
def recursive_order(order=0):
compared = 0
for fooa in [foo for foo in foos if foo.order >= order]:
for foob in [foo for foo in foos if foo.order >= order]:
compared += 1
if fooa in foob.depends_on:
foob.order += 1
if compared == 0:
return
recursive_order(order + 1)
recursive_order()
foos.sort(key=lambda foo: foo.order)
print [(foo.name, foo.order) for foo in foos]
[('a', 0), ('d', 0), ('e', 0), ('b', 1), ('f', 1), ('c', 2), ('g', 2)]
我想要一个考虑“依赖顺序”的foo
列表。例如,foo a和foo b没有依赖关系,因此是相等的。 Foo b依赖于Foo a,所以foo a< foo b([a,b] .Foo c取决于Foo b,所以[a,b,c]。
修改
感谢Martijn Pieters提供拓扑排序的链接。这是我的实施:
def topological_sort(foos):
provided = set()
while foos:
remaining_foos = []
emitted = False
for foo in foos:
if set(foo.depends_on).issubset(provided):
yield foo
provided.add(foo)
emitted = True
else:
remaining_foos.append(foo)
if not emitted:
raise raise ValueError("cyclic dependency detected")
foos = remaining_foos
print [foo.name for foo in topological_sort(foos)]
['e', 'd', 'a', 'f', 'b', 'g', 'c']