-1

As in title, how can I sort objects by single criterion?

I've heard about key parameter, cmp parameter, and Decorate-Sort-Undecorate pattern.
Which one should I use in modern Python, and how?

smci
  • 32,567
  • 20
  • 113
  • 146
GingerPlusPlus
  • 5,336
  • 1
  • 29
  • 52
  • This is my attempt to create [canonical question for sorting with key argument in Python](http://meta.stackoverflow.com/q/314445/3821804). – GingerPlusPlus Jan 18 '16 at 22:27
  • Please note that even self-answered questions should meet the site's quality requirements; see [ask]. *"How to"* questions aren't a good for for SO, consider writing this up on a blog or something. – jonrsharpe Jan 18 '16 at 22:27
  • @jonrsharpe: at the moment, I really have no idea how I could improve the question, while keeping it case-agnostic; I'll think about it again tomorrow. What do you mean by *writing this up on a blog*? (English is not my first language) – GingerPlusPlus Jan 18 '16 at 22:35
  • I mean post this as an article on a blog, rather than trying to shoe-horn it onto SO. – jonrsharpe Jan 18 '16 at 22:36
  • I edited the title to be more specific, and voted to reopen – smci Apr 24 '18 at 21:13

1 Answers1

3

In modern Python, the best way is to use list.sort or sorted with key argument.

When you pass key argument, sorting function, instead of comparing elements directly, compares whatever key returned for them.

So, you can pass as key any callable that takes element to be sorted as single positional argument, and returns what the element should be sorted by.
The callable will be called once for each element.

Some simple examples:

   list_ = ['B', 'aaa', 'CC']

   sorted(list_)
=> ['B', 'CC', 'aaa']

   # case-insensitive sorting
   sorted(list_, key=str.lower)
=> ['aaa', 'B', 'CC']

   # sorting by length
   sorted(list_, key=len)
=> ['B', 'CC', 'aaa']

Sorting with key is roughly equivalent to Decorate-Sort-Undecorate pattern:

def decorate_sort_undecorate(iterable, key):
    # 1: decorate:
    decorated = [(key(elem), index, elem) for index, elem in enumerate(iterable)]

    # 2: sort:
    decorated.sort()

    # 3: undecorate: 
    return [elem for key_, index, elem in decorated]

This creates temporary list (decorated) of 3-element tuples,
which have form: (key_, index, elem), where key_ = key(elem). Then, decorated list is sorted.
Tuples are compared by first non-equal element. This is key_, or if key_s are equal, index. Because there are no equal indexes, elements are never directly compared.
At the end, elements are extracted from decorated into new list, which is returned.

Random thoughts:

Community
  • 1
  • 1
GingerPlusPlus
  • 5,336
  • 1
  • 29
  • 52