2017-11-17 201 views
0

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

输入:

  • result =与用户ID(user.id)IDS例如用户
  • list_of_ids =列表中的用户的对象列表[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 
+1

这不是很清楚你的要求。 –

+0

结果列表,它在哪里?你是怎么计算的? –

+1

@martineau我很确定它不是重复的,至少不是你引用的Q.观察一下_unsorted_列表给出的期望顺序是如何产生的,这是一个非常不同的问题。特别是,仅将属性作为关键字进行排序不是解决方案。 –

回答

3

你可以先将用户的字典:

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

然后你有几种选择,根据通过id查找用户,例如:

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

编辑:我可能,除非你有一个非常名单或者有很多次执行操作,不用担心效率那么多,而是专注于清晰和可读。

1

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

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'}] 
+1

小心,在这里。使用'ids.index(obj [“id”])'是一个O(N)操作,使排序操作的总数为O(n^2logn) –

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 
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)]