0

I am attempting to sort a list of lists by each index of the inner list. (All inner lists are the same length.) The goal is to sort the rows by the last column (the last index of the inner lists) first, then by the previous column/index and so on.

Input:

[
  ['2016', 'E', None, '68', '94'],
  ['2016', 'A', None, '91', '25'],
  ['2016', 'C', None, '74', '25'],
  ['2017', 'C', None, '55', '20'],
  ['2015', 'D', None, '20', '14'],
  ['2016', 'B', None, '66', '66'],
  ['2017', 'E', None, '29', '41'],
  ['2017', 'F', None, '61', '22'],
  ['2015', 'A', None, '17', '96']
]

Output:

[
  ['2015', 'A', None, '17', '96'],
  ['2015', 'D', None, '20', '14'],
  ['2016', 'A', None, '91', '25'],
  ['2016', 'B', None, '66', '66'],
  ['2016', 'C', None, '74', '25'],
  ['2016', 'E', None, '68', '94'],
  ['2017', 'C', None, '55', '20'],
  ['2017', 'E', None, '29', '41'],
  ['2017', 'F', None, '61', '22']
]

I have the following piece of code that I'm trying to use for this:

def sort_table(column_count, rows)
  for i in range(len(column_count) - 1, -1, -1):
    rows = sorted(rows, key=operator.itemgetter(i))
  return rows

However, it seems to be thrown by the fact that there are or can be None values in the list. I keep getting the error TypeError: '<' not supported between instances of 'NoneType' and 'str'. Is there a correct way to handle this?

ebbishop
  • 1,833
  • 2
  • 20
  • 45
  • 1
    https://stackoverflow.com/questions/12971631/sorting-list-by-an-attribute-that-can-be-none – Rockybilly Oct 19 '17 at 17:39
  • 1
    Just use [`sorted`](https://docs.python.org/dev/library/functions.html#sorted) – Patrick Haugh Oct 19 '17 at 17:41
  • @PatrickHaugh - I am using sorted. What should I be doing differently? – ebbishop Oct 19 '17 at 17:44
  • 1
    Your sample output isn't sorted by the last column, then the previous one and so on. Instead, it's sorted by the first column and then all the next ones. – Unatiel Oct 19 '17 at 17:47
  • @Unatiel We're both correct, just saying it differently. I'm first sorting by the last column, so that the first column is the largest group. – ebbishop Oct 19 '17 at 18:14

2 Answers2

3

Use sorted on your multidimensional list

l = [
  ['2016', 'E', None, '68', '94'],
  ['2016', 'A', None, '91', '25'],
  ['2016', 'C', None, '74', '25'],
  ['2017', 'C', None, '55', '20'],
  ['2015', 'D', None, '20', '14'],
  ['2016', 'B', None, '66', '66'],
  ['2017', 'E', None, '29', '41'],
  ['2017', 'F', None, '61', '22'],
  ['2015', 'A', None, '17', '96']
]
print(sorted(l))

prints

[['2015', 'A', None, '17', '96'], ['2015', 'D', None, '20', '14'], ['2016', 'A', None, '91', '25'], ['2016', 'B', None, '66', '66'], ['2016', 'C', None, '74', '25'], ['2016', 'E', None, '68', '94'], ['2017', 'C', None, '55', '20'], ['2017', 'E', None, '29', '41'], ['2017', 'F', None, '61', '22']]

Which is the same as your required output

Patrick Haugh
  • 59,226
  • 13
  • 88
  • 96
  • 1
    Or if you do want the sorting done by the last index (as in the description but not the sample output) use `sorted(l, key=reversed)` – Holloway Oct 19 '17 at 17:58
  • @Holloway It's not that I want to sort in the opposite order from the one I showed in the results, it's just that I though I'd need to sort each index separately, so I was working my way backwards through the indices to get the desired effect. – ebbishop Oct 19 '17 at 18:16
1

Apart from the key, the sorted function also allows you to customize the comparator function, by passing a cmp argument. Just pass a function of two arguments that returns negative if the first argument is smaller, positive if it is larger, zero if they are equal. Depending on what you want, you could do something like

 import numpy as np

 def mycomparator(a, b):
     if a is None:
        return -1
     return np.sign(a - b)

 sorted(..., cmp=mycomparator, key=...)
blue_note
  • 27,712
  • 9
  • 72
  • 90