基于2个类属性的Python排序

时间:2017-03-03 10:33:30

标签: python sorting

编辑:刚刚发现我正在使用py 2.6.2(已安装工作,因此我无法做太多)

所以我试图找到基于2个不同类属性对列表进行排序的最佳方法

这个列表基本上是一些信息,用于在一家公司中将人们从一个房间移动到另一个房间,在这个公 (即Joe Blow在我们将Jane Doe移动到Joe的位置之前必须移动而Jane必须在John Wick移动到Jane的位置之前移动。)

我得到的信息如下所示,但在下面的示例中,也可能有人像Dan Man一样不属于链条移动。

John Wick 303.10 -> 415.09
Dan Man 409.08 -> 221.02
Joe Blow 225.06 -> 512.01
Jane Doe 415.09 -> 225.06

我将所有相关信息拆分为

startRoom
endRoom
originalString

所以那个部分不是问题但是当我尝试“暴力”时将其排序如下:(注意,我做列表(链),因为它以前是一套,以确保我没有得到双打在那里)

def sortChains():
    global chains
    #convert the set of chains to a list for list functions

    chains = list(chains)
    for x, move1 in enumerate(chains):
        for y, move2 in enumerate(chains):
            if move1.startRoom == move2.endRoom:
                temp = chains[y]
                chains.remove(move2)
                chains.insert(x,temp)
                continue

我的问题是排序。问题的一部分是找到链条起点的人员,然后在此之后正确排序。 任何想法/帮助是完全赞赏的。是的,我知道一个双循环,而在循环中移动东西不是最好的,但它是我当时想到的最好的。

2 个答案:

答案 0 :(得分:2)

首先,你必须创建一个依赖图并确定(a)哪个人必须移动moves = {"John Wick": ("303.10", "415.09"), "Dan Man": ("409.08", "221.02"), "Joe Blow": ("225.06", "512.01"), "Jane Doe": ("415.09", "225.06")} # or dict((move.originalString, (move.startRoom, move.endRoom)) for move in list_of_moves) # mapping {initial room -> name} rooms = {start: name for (name, (start, end)) in moves.items()} # Python 2.6: dict((start, name) for (name, (start, end)) in moves.items()) # mapping {moves_first: moves_after} before = {rooms[end]: name for name, (start, end) in moves.items() if end in rooms} # Python 2.6: dict((rooms[end], name) for name, (start, end) in moves.items() if end in rooms) # persons that can move now can_move = set(moves) - set(before.values()) 其他人可以移动,以及(b)哪些人现在可以移动。我们可以在这里使用1:1映射,但在更一般的情况下,您可能必须使用1:n,n:1或n:m映射。

result = []
while can_move:
    # get person that can move, add to result
    name = can_move.pop()
    result.append(name)
    # add next to can_move set
    if name in before:
        can_move.add(before.pop(name))

现在,我们可以看到谁可以移动,移动那个人,然后根据必须等待该人移动的人(如果有的话)更新可以移动的人。

result

之后,['Joe Blow', 'Jane Doe', 'John Wick', 'Dan Man']为{{1}}

复杂性应该是O(n),但当然,如果存在循环依赖性,这将失败。

答案 1 :(得分:0)

def do(moves):
    """RETURNS: [0] Sequence of persons to move.
                [1] Remainder
    """
    # (following line copied from 'tobias_k', replaced 'rooms' with 'current_db')
    # map: target position to person who occupies it
    current_db = { start: name for (name, (start, end)) in moves.items() }
    # maintain set of persons who are free to move to their target location
    liberated_set = set()
    # map occupier of a location -> set of people who would take his place.
    liberation_db = defaultdict(set)
    # whosoever wants to move to a free place -> liberated.
    # else                                    -> liberation_db
    for name, (start, end) in moves.items():
        occupier = current_db.get(start)
        if occupier is None: liberated_set.add(name)
        else:                liberation_db[occupier].add(name)

    sequence = []
    while liberated_set:
        # add people to the sequence who are free to move
        sequence.extend(liberated_set)
        # get new set of people who are free to move to their target
        # because their target position is no longer occupied.
        new_liberated_set = set()
        for occupier in liberated_set:
            if not occupier in liberation_db: continue
            new_liberated_set.extend(liberation_db[occupier])
            del liberation_db[occupier]
        liberated_set = new_liberated_set

     return sequence, set(liberation_db.values())