5

I have some custom objects and dictionaries that I want to sort. I want to sort both the objects the dictionaries together. I want to sort the objects by an attribute and the dictionaries by a key.

object.name = 'Jack'
d = {'name':'Jill'}

sort_me =[object, d]

How do I sort this list using the object's name attribute and the dictionary's 'name' key?

4 Answers 4

8

What you are almost certainly looking for is to use the key= option for sorted(), which provides a function which returns an arbitrary sort key for each element. This function can check the type of its argument and take various actions. For instance:

import types

class obj(object):
    def __init__(self, arg):
        self.name = arg

def extract_name(obj):
    if type(obj) is types.DictType:
        return obj['name']
    else:
        return obj.__dict__['name']

d = { 'name': 'Jill'}    
print sorted([obj('Jack'), d], key=extract_name)

More information can be found on the Python wiki

RichieHindle's suggestion of using isinstance is a good one. And while I was at it I thought it might be nice to support arbitrary element names instead of hardcoding 'name':

def extract_elem_v2(elem_name):
    def key_extractor(obj):
        dct = obj if isinstance(obj, dict) else obj.__dict__
        return dct[elem_name]
    return key_extractor

Which you can use like so:

print sorted(list_of_stuff, key=extract_elem_v2('name'))
Sign up to request clarification or add additional context in comments.

5 Comments

+1. Minor suggestion: isinstance(obj, dict) would be neater, and would allow for classes derived from dict.
You're right, isinstance is a better choice there, not sure why I didn't think of that. Updated version appended to the answer. Thanks!
Thanks a lot Jack! This answer is beautiful.
__dict__ attribute is not available for all objects.
A) Corrections inline, that's what people read. The type(..) is thing has 0 merit to stay. B) is vars(obj) preferred over obj.__dict__? (vars is a less known builtin.)
3
sort_me.sort(key=attr_or_itemgetter('name'))

Where attr_or_itemgetter():

class attr_or_itemgetter(object):
    def __init__(self, name):
        self.name = name
    def __call__(self, obj):
        try: return getattr(obj, name)
        except AttributeError:
            return obj[name]

NOTE: It intentionally doesn't check for dictionary type, therefore attr_or_itemgetter('items') applied to a dictionary will return dict.items method.

1 Comment

I find this answer more Pythonic than the one based on type-checking (may be a little slower if there are plenty of dicts in the sequence being sorted, but all it takes to optimize it for that use is flipping what's the try body & what's the except body, and catching different exceptions;-0).
1

This worked for me. Note that sort() does not return the sorted list, but sorted() does, so if you want to pass this to a template, you should use sorted in the parameters, or sort before you pass the list as a parameter.

itemized_action_list = list(chain(detection_point.insertbodyaction_set.all(),
                                  detection_point.insertheaderaction_set.all(),
                                  detection_point.modifybodyaction_set.all(),
                                  detection_point.modifyheaderaction_set.all(),
                                  detection_point.removebodyaction_set.all(),
                                  detection_point.removeheaderaction_set.all(),
                                  detection_point.redirectaction_set.all()))

sorted(itemized_action_list, key=attrgetter('priority'))

1 Comment

Welcome to SO. Try to be clear and precise in your examples. Without no additional info it is not possible to say what your list contains.
1

new_list = [10,"m",20,30,"a","r",70,"d"]

def func(x):

if type(x) == str:

    return ord(x)+100

return x

new_list.sort(key=func)

print(new_list)

[10, 20, 30, 70, 'a', 'd', 'm', 'r']

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.