排序/图形遍历顺序的对象列表"依赖"在彼此身上

时间:2014-11-02 00:46:31

标签: python python-2.7

我有一个像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']

0 个答案:

没有答案