Python根据另一个列表中的属性顺序对对象列表进行排序

4

我正在使用Python列表排序。

我有两个列表:一个是整数列表,另一个是对象列表,第二个对象列表具有属性id,它也是一个整数。 我想根据id属性对对象列表进行排序,并以相同id出现在第一个列表的顺序排序,好的,这是一个例子:

我得到了 a = [1,2,3,4,5]

b = [o,p,q,r,s],其中 o.id = 2,p.id = 1,q.id = 3,r.id = 5,s.id = 4

我希望我的列表 b 根据其id在列表a中出现的顺序进行排序,像这样:

sorted_b = [p, o, q, s, r]

当然,我可以使用嵌套循环来实现这一点:

sorted_b = []
for i in a:
    for j in b:
        if j.id == i:
            sorted_b.append(j)
            break

但这是一个典型的丑陋而不符合Python习惯的解决问题的方式,我想知道是否有一种更加整洁的方法来解决这个问题,例如使用sort方法,但我不知道怎么做。

4个回答

8
>>> from collections import namedtuple
>>> Foo = namedtuple('Foo', 'name id') # this represents your class with id attribute
>>> a = [1,2,3,4,5]
>>> b = [Foo(name='o', id=2), Foo(name='p', id=1), Foo(name='q', id=3), Foo(name='r', id=5), Foo(name='s', id=4)]
>>> sorted(b, key=lambda x: a.index(x.id))
[Foo(name='p', id=1), Foo(name='o', id=2), Foo(name='q', id=3), Foo(name='s', id=4), Foo(name='r', id=5)]

2
这是一种简单的方法:

这是一个简单的做法:

# Create a dictionary that maps from an ID to the corresponding object
object_by_id = dict((x.id, x) for x in b)

sorted_b = [object_by_id[i] for i in a]

如果列表变得很大,这也可能是最快的方法。

太棒了!我喜欢你解决这个问题的方式,非常感谢! - Roger Liu

1
你可以使用列表推导式来完成,但通常情况下是相同的。
sorted_b = [ y for x in a for y in b if y.id == x ]

我认为jamylak的回答是我正在寻找的,但无论如何还是谢谢:) - Roger Liu

0
Python中有一个sorted函数。它接受可选的关键字参数cmp。您可以在那里传递自定义的排序函数。
来自文档的cmp定义:

自定义比较应返回负数、零或正数,具体取决于第一个参数是否被认为小于、等于或大于第二个参数

a = [1,2,3,4,5]
def compare(el1, el2):
   if a.index(el1.id) < a.index(el2.id): return -1
   if a.index(el1.id) > a.index(el2.id): return 1
   return 0

sorted(b, cmp=compare)

这个更加直接,然而我鼓励你使用key参数,就像jamylak在他的回答中所描述的一样,因为它更符合Python的风格,在Python 3中不再支持cmp


但是我对 compare 函数中的两个 if 语句有些困惑,你能为我解释一下吗?我不熟悉 cmp 参数,谢谢。 - Roger Liu
那么我认为第二个if语句应该是如果a.index(el1.id) > a.index(el2.id)。现在我明白了,谢谢你的帮助。 - Roger Liu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接