如何使用对象属性列表来排序对象列表

时间:2017-11-17 23:38:52

标签: python

我有一个带有id的对象列表(object.id)和一个id列表。使用id列表排序对象列表的最有效方法是什么?我有以下解决方案......只是想知道是否有更快的解决方案?

输入:

  • result =具有用户ID的用户对象列表(user.id)
  • list_of_ids =用户ID列表,例如[3, 2, 5, 8, 9]

输出:

  • 根据list_of_ids
  • 订购的用户对象列表

代码:

ordered_result = []
for user_id in list_of_ids:
    for user in result:
        if user_id == user.id:
            ordered_result.append(user)
            break

4 个答案:

答案 0 :(得分:3)

您可以先将用户置于词典中:

usrdict = {}
for user in result:
    usrdict[user.id] = user

然后,根据用户id查找用户,您可以选择一些选项,例如:

ordered_result = [usrdict[x] for x in list_of_ids]

编辑:我可能,除非你有一个非常大的列表或执行很多次的操作,不要担心效率那么多,而是注重使其清晰可读。

答案 1 :(得分:1)

您可以使用sorted功能和自定义排序功能。在这种情况下,在ids列表中返回索引。

def order_by(objects, ids):
    def fn(obj):
        return ids.index(obj["id"])

    return sorted(objects, key=fn)

print(order_by(objects_list, id_list))

示例:

objects_list = [
{ "id": 3, "name": "penny"},
{ "id": 5, "name": "adam"},
{ "id": 9, "name": "meh"},
{ "id": 1, "name": "john"},
{ "id": 3, "name": "archibald"},
]
id_list = [9,1,3,5,6,4]

print(order_by(objects_list, id_list))

结果:

[{'id': 9, 'name': 'meh'}, {'id': 1, 'name': 'john'}, {'id': 3, 'name': 'penny'}, {'id': 3, 'name': 'archibald'}, {'id': 5, 'name': 'adam'}]

答案 2 :(得分:0)

这是一个O(n log(n))解决方案。它要求两个列表中的ID完全相同。它按id对对象列表进行排序,并对id列表进行间接排序,从而产生一个包含id的位置的索引列表。然后使用它将已排序的对象移动到正确的位置。

import operator

class know_who_you_are:
    def __init__(self, id_):
        self.id = id_

def argsort(L):
    "returns sorted, order"
    return zip(*sorted(zip(L, range(len(L)))))

ids = [3, 2, 4, 5, 1]
objs = [know_who_you_are(id_) for id_ in [1, 5, 3, 2, 4]]

sid, oid = argsort(ids)
sobj = sorted(objs, key=operator.attrgetter('id'))
result = len(objs) * [None]
for dest, src in zip(oid, sobj):
    result[dest] = src

# check
print(all(id_==obj.id for id_, obj in zip(ids, result)))

打印:

True

答案 3 :(得分:0)

这里是使用带有自定义比较功能的内置sorted()函数的方案的变体。 (它可能看起来像很多代码,但其中很大一部分仅用于设置一个有点现实的测试用例。)

from functools import cmp_to_key
import random

random.seed(13)  # Gets consistent "random" ordering during testing.

class User:
    def __init__(self, name, id):
        self.name = name
        self.id = id

    def __repr__(self):
        return '{}({!r}, id={!r})'.format(self.__class__.__name__, self.name, self.id)

@cmp_to_key  # Converts cmp function to a key function.
def cmp(x, y):
    """ Return -1 if the position of User x in list_of_ids < index of User y
        otherwise return 1.
    """
    p1, p2 = -1, -1
    try:
        p1 = list_of_ids.index(x.id)
        p2 = list_of_ids.index(y.id)
    except ValueError:
        pass
    return -1 if p1 < p2 else 1

list_of_ids = [3, 2, 5, 8, 9]
# Create a random list of users with these ids.
shuffled_ids = random.sample(list_of_ids, k=len(list_of_ids))
users = [User(name, id) for name, id in zip(['Andy', 'Simon', 'Nick', 'John',
                                             'Roger'], shuffled_ids)]

print('Desired id order:', list_of_ids)
print()
print(' Before:', users)
ordered_result = sorted(users, key=cmp)
print('Ordered:', ordered_result)

输出:

Desired id order: [3, 2, 5, 8, 9]

 Before: [User('Andy', id=5), User('Simon', id=9), User('Nick', id=8), User('John', id=3), User('Roger', id=2)]
Ordered: [User('John', id=3), User('Roger', id=2), User('Andy', id=5), User('Nick', id=8), User('Simon', id=9)]