基于2个类属性的Python排序
编辑:刚刚发现我使用的是py 2.6.2(安装了工作,所以我对此无能为力) 因此,我试图找到根据两个不同的类属性对列表进行排序的最佳方法 该列表基本上是一些信息,用于在一家公司内将人员从一个房间移动到另一个房间,其中一些人可能是连锁移动的一部分 (也就是说,乔·布鲁必须在我们将简·多伊转移到乔的位置之前移动,简必须在约翰·威克转移到简的位置之前移动,等等) 我得到了如下所示的所有信息,但也可能有一些人不属于链的一部分,比如下面示例中的Dan Man基于2个类属性的Python排序,python,sorting,Python,Sorting,编辑:刚刚发现我使用的是py 2.6.2(安装了工作,所以我对此无能为力) 因此,我试图找到根据两个不同的类属性对列表进行排序的最佳方法 该列表基本上是一些信息,用于在一家公司内将人员从一个房间移动到另一个房间,其中一些人可能是连锁移动的一部分 (也就是说,乔·布鲁必须在我们将简·多伊转移到乔的位置之前移动,简必须在约翰·威克转移到简的位置之前移动,等等) 我得到了如下所示的所有信息,但也可能有一些人不属于链的一部分,比如下面示例中的Dan Man John Wick 303.10 ->
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
所以这一部分不是问题,但当我尝试“暴力”排序时,如下所示:(注意,我做列表(链),因为它以前是一个集合,以确保我不会在其中得到双倍)
我的问题是分类。问题的一部分是找到位于链起点的人,然后正确排序。
非常感谢您的任何想法/帮助。是的,我知道在循环中移动东西时出现双循环不是最好的,但这是当时我能想到的最好的方法。首先,你必须创建一个依赖关系图,并确定(a)在其他人可以移动之前,哪些人必须移动
,以及(b)哪些人现在可以移动。我们可以在这里使用1:1映射,但在更一般的情况下,可能必须使用1:n、n:1或n:m映射
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())
现在,我们可以看到谁可以移动,移动那个人,然后根据那个人需要等待什么来更新可以移动的人,如果有的话
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))
之后,结果是['Joe Blow'、'Jane Doe'、'John Wick'、'Dan Man']
复杂性应该是O(n),但当然,如果存在循环依赖,这将失败。您将如何排序[(A,1,2),(B,2,1)]
?链是否需要保持分组?或者在你的例子中输出Joe->Dan->Jane->John
可以吗?@adrio会很好,因为我有另一个循环要通过,并在链之间添加一个间隔(因为可能有多个)你能确保:1)所有给定的移动都是可行的(即没有两个具有相同值的尾端空间)2)没有循环移动吗(例如,A移动到B的位置,B移动到C的位置,C移动到A的位置)对于任何数量的人,考虑到如果人A从A移动到B,然后从B移动到C,并且人B从d移动到B,这不符合1)。但是,这仍然是一个有效的移动,因为a将在c中结束,B将在B中结束。对于您和Tobias的房间={start:name For(name,(start,end))in moves.items()}会在For处导致无效语法keyword@TEvashkevich然后,您使用的是非常旧的Python版本,可能是2.6或更旧的版本。查看我的编辑。你能添加几行吗?这与我的版本有什么不同/更好的地方吗?@tobias_k刚刚检查过,你是对的。它显然是2.6.2(我以为我使用的是更新的版本,但不幸的是不是我的决定)@tobias_k我刚才在我简单复制的第一行中提到了你。其余部分明显不同。编辑后肯定更接近。现在说这个列表并没有属性,我只是试着用枚举(移动)来代替,但说的是TypeError:iteration over non sequence。如果我只是删除.items也是一样的错误…所以关闭编辑:另外,为了澄清,上面代码中的开始/结束应该是我的startRoom/endRoom正确吗?@TEvashkevich键入(移动)
说什么?它应该是一个目录
,而不是列表
。您是否定义了一个函数dict
,隐藏了dict
bultin函数?啊,我把它列为一个列表,因为我的东西只是从一个txt文件中读取的,我把它放在了我前面提到的类中。我想我可以重新写一封信,把它扔进一个dict@TEvashkevich查看另一个编辑,了解如何从Move
对象列表创建dict。哦,很好,我不知道你可以这样做只是为了制作一本字典!谢谢你,老兄,你完全解决了我的难题
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())
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())