dabadaba
dabadaba

Reputation: 9522

Sorting by attributes that can be None

Let's say I have a list of items I want to sort: items = [ item1, item2, item3 ]. The attribute I want to use to sort them is item.data.value, so I'd normally go:

sorted(items, key=attrgetter('data.value'))

And that'd work just fine. However, data can actually be None so obviously I couldn't access value.

How do you usually deal with scenarios like this?

PS: neither this question nor this one helped.

Upvotes: 7

Views: 3701

Answers (6)

internety
internety

Reputation: 374

attrgetter with default value support.

behaves like dictionary.get()

D.get(k[,d]) -> D[k] if k in D, else d

d defaults to None. detailed info: groups.google.com:python-ideas

Upvotes: -1

thiruvenkadam
thiruvenkadam

Reputation: 4260

Just filter the None values first before sending them to sorted.

sorted(filter(None, items), key=attrgetter('data.value'))

And if you really want the None items too, you can do something like this:

# items already defined with values
new_items_list = sorted(filter(None, items), key=attrgetter('data.value'))
new_items_list.extend([None] * (len(items) - len(new_items_list)))

However, I am not sure whether you really need the None items.

EDIT: Fixed the end code which will retain the None items.

Upvotes: 0

RemcoGerlich
RemcoGerlich

Reputation: 31270

Use as key a tuple, like (False, value). If value is None, then the tuple should be (True, None).

Tuples are compared by their first element first, then the second, et cetera. False sorts before True. So all None values will be sorted to the end.

def none_to_end_key(item):
    value = item.data.value if item.data else None
    return (value is None, value)

sorted(items, key=none_to_end_key)

Will sort all None values to the end.

I see now that you have tagged your question Python-2.7, then this is probably overkill. In Python 3, comparing None to an integer or string raises an exception, so you can't simply sort a list with None and other values, and something like this is needed.

Upvotes: 3

Sergey Gornostaev
Sergey Gornostaev

Reputation: 7797

sorted(items, key=lambda i: i.data.value if i.data else 0)

Upvotes: 7

Stop harming Monica
Stop harming Monica

Reputation: 12610

If you do not have a function handy that returns the key you want then just write your own.

def item_key(item):
    try:
        return item.data.value
    except AttributeError:
        return None

sorted(items, key=item_key)

Upvotes: 0

armak
armak

Reputation: 560

just filter for the None before sorting

sorted(filter(None, items), key=attrgetter('data.value'))

Upvotes: 2

Related Questions