简体   繁体   中英

Sort a list of dictionaries by values with some items missing

I have a dict of lists like this:

a = [
   {'p': 3, 'id': 'ab1'},
   {'p': 10, 'id': 'ab2'},
   {'p': 5, 'id': 'ab3'},
   {'p': 8, 'id': 'ab4'},
   {'id': 'ab5'}
]

I want to sort a by the value of p . If dict doesn't has p , put it behind. I tried this way:

print sorted(a, key=lambda i: i.get('p'))

and got result:

[{'id': 'ab5'}, {'p': 3, 'id': 'ab1'}, {'p': 5, 'id': 'ab3'}, {'p': 8, 'id': 'ab4'}, {'p': 10, 'id': 'ab2'}]

but want to get is:

[{'p': 3, 'id': 'ab1'}, {'p': 5, 'id': 'ab3'}, {'p': 8, 'id': 'ab4'}, {'p': 10, 'id': 'ab2'},{'id': 'ab5'}]

What can I do to get the correct result with easier way?

For python2 and python3 both, you can do as follows, where I assume if the value of p is missing, I am assuming sys.maxsize value, which will ensure that if we have missing values for p , they are always at the end of the list

import sys
a = [
   {'p': 3, 'id': 'ab1'},
   {'p': 10, 'id': 'ab2'},
   {'p': 5, 'id': 'ab3'},
   {'p': 8, 'id': 'ab4'},
   {'id': 'ab5'}
]

print(sorted(a, key=lambda i: i.get('p', sys.maxsize)))

Which will give you

[{'p': 3, 'id': 'ab1'}, {'p': 5, 'id': 'ab3'}, {'p': 8, 'id': 'ab4'}, {'p': 10, 'id': 'ab2'}, {'id': 'ab5'}]

Another solution if comparing to sys.maxsize is overkill, is to separate out the dictionaries without the key p , sort the remaining dictionary which contain the key p , and then extend it by attaching the non p key dictionaries like so. This also avoids us from providing a default value for p in item.get()

import sys
a = [
   {'p': 3, 'id': 'ab1'},
   {'p': 10, 'id': 'ab2'},
   {'p': 5, 'id': 'ab3'},
   {'p': 8, 'id': 'ab4'},
   {'id': 'ab5'}
]

#Dictionaries with key p
p_items = [item for item in a if 'p' in item.keys()]

#Dictionaries not with key p
non_p_items = [item for item in a if 'p' not in item.keys()]

#Sort the p-key dictionaries
result = sorted(p_items, key=lambda i: i.get('p'))

#Attach non p-key dictionay items at end
result.extend(non_p_items)

print(result)

Use

a = [
   {'p': 3, 'id': 'ab1'},
   {'p': 10, 'id': 'ab2'},
   {'p': 5, 'id': 'ab3'},
   {'p': 8, 'id': 'ab4'},
   {'id': 'ab5'}
]

print(sorted(a, key=lambda i: i.get('p', "NA"))) #Setting a string as a default value. 
#python 3  --> https://stackoverflow.com/questions/49829732/sorting-a-mixed-list-of-ints-and-strings
print(sorted(a, key=lambda v: (isinstance(v.get('p', "NA"), str), v.get('p', "NA"))))

Output:

[{'p': 3, 'id': 'ab1'}, {'p': 5, 'id': 'ab3'}, {'p': 8, 'id': 'ab4'}, {'p': 10, 'id': 'ab2'}, {'id': 'ab5'}]

Here's an option that I prefer that doesn't use lambda :

import sys
from operator import methodcaller

a = [
   {'p': 3, 'id': 'ab1'},
   {'p': 10, 'id': 'ab2'},
   {'p': 5, 'id': 'ab3'},
   {'p': 8, 'id': 'ab4'},
   {'id': 'ab5'}
]

print(sorted(a, key=methodcaller('get', 'p', sys.maxsize)))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM