0

I've got a list of objects of the following format:

obj = [{"id": 39, "name":"bla"},{"id": 23, "name":"blabla"},{"id": 45, "name":"blabla"},{"id": 12, "name":"blabla"},{"id": 100, "name":"blabla"},...]

I also have a list of IDs (A) defined as follows:

A = [23,39,45,...]

I need to sort obj such that all the sorting reflects the order of A - the first object is the one with key 23, the second one with key 39 and so on.

I'm thinking of using zip for this but not sure exactly how to do so - would I need to zip the two lists together and then sort the zipped list of tuples?

Alk
  • 5,215
  • 8
  • 47
  • 116
  • What should happen if two objects have the same id? What should happen if `A` contains the same number more than once? What should happen if an object has an id that isn't present in `A`? ("I'm completely sure that will never happen" is a legitimate answer to any of these.) – Kevin Jun 06 '19 at 15:59
  • 1
    Another relevant duplicate [here](https://stackoverflow.com/questions/25624106/sort-list-of-dictionaries-by-another-list) – Sheldore Jun 06 '19 at 15:59

3 Answers3

2

First construct a mapping that allows you to look up an item by its id:

In [6]: index = {item["id"]: item for item in obj}                                         

In [7]: index                                                                              
Out[7]: 
{39: {'id': 39, 'name': 'bla'},
 23: {'id': 23, 'name': 'blabla'},
 45: {'id': 45, 'name': 'blabla'},
 12: {'id': 12, 'name': 'blabla'},
 100: {'id': 100, 'name': 'blabla'}}

then pick them one by one from this mapping:

In [8]: [index[id] for id in A]                                                            
Out[8]: 
[{'id': 23, 'name': 'blabla'},
 {'id': 39, 'name': 'bla'},
 {'id': 45, 'name': 'blabla'}]
Kos
  • 70,399
  • 25
  • 169
  • 233
1

You could enumerate A and keep track of the indices in a dict:

order = {val:i for i, val in enumerate(A)}

# second arg in get could be for any invalid entries
x = sorted(obj, key = lambda x: order.get(x['id'], 99))

# [{'id': 23, 'name': 'blabla'}, {'id': 39, 'name': 'bla'}, {'id': 45, 'name': 'blabla'}, {'id': 12, 'name': 'blabla'}, {'id': 100, 'name': 'blabla'}]

Where it will now sort by the position in A. However, if you have duplicates in A, this will take the last index of the element to be the sort order:

# no dupes
{x: i for i, x in enumerate([1,2,3])}
# {1: 0, 2: 1, 3: 2}

# dupes
{x: i for i, x in enumerate([1,2, 1, 3])}
# {1: 2, 2: 1, 3: 3}

Which would put 1 after 2, even though you might want the opposite

C.Nivs
  • 12,353
  • 2
  • 19
  • 44
0

Create a dict from obj and then build a list with the order you want

    d = {item['id']: item for item in obj} 
    new_list = [d[i] for i in A]
DanielM
  • 3,598
  • 5
  • 37
  • 53