3

I'm having an issue with sorting a list that contains a dict. Currently I am sorting it by a key called 'title' with the following line:

list.sort(key=operator.itemgetter('title'))

The problem with this is that some of my data gets sorted looking like this:

title_text #49
title_text #5
title_text #50

How would I go about sorting it in a way that is more friendly for human consumption while still maintaining the title sort?

sth
  • 222,467
  • 53
  • 283
  • 367
wierddemon
  • 33
  • 2
  • any chance you can make your numbers 0-padded on the left? i.e. title_text #5 to be `title_text #05` - then you won't need to 'fix' the sort – Nas Banov Jul 13 '10 at 05:44

3 Answers3

4

You are looking for human sorting.

import re
# Source: http://nedbatchelder.com/blog/200712/human_sorting.html
# Author: Ned Batchelder
def tryint(s):
    try:
        return int(s)
    except:
        return s

def alphanum_key(s):
    """ Turn a string into a list of string and number chunks.
        "z23a" -> ["z", 23, "a"]
    """
    return [ tryint(c) for c in re.split('([0-9]+)', s) ]

def sort_nicely(l):
    """ Sort the given list in the way that humans expect.
    """
    l.sort(key=alphanum_key)

data=[
    'title_text #49',
    'title_text #5',
    'title_text #50']
sort_nicely(data)
print(data)
# ['title_text #5', 'title_text #49', 'title_text #50']

Edit: If your data is a list of dicts then:

data=[{'title': 'title_text #49', 'x':0},
      {'title':'title_text #5', 'x':10},
      {'title': 'title_text #50','x':20}]

data.sort(key=lambda x: alphanum_key(x['title']))
# [{'x': 10, 'title': 'title_text #5'}, {'x': 0, 'title': 'title_text #49'}, {'x': 20, 'title': 'title_text #50'}]
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • I got that far, but how would you do that if your data contained a dict with multiple values including the title (which I am wanting to sort with)? – wierddemon Jul 12 '10 at 19:15
  • @wierddemon: The heart of the human sorting technique lies in `alphanum_key`. For a list of dicts, you could use it like this: `data.sort(key=lambda x: alphanum_key(x['title']))`. See above. – unutbu Jul 12 '10 at 19:44
2

You're looking for a Natural Sort. Start here:

Python analog of natsort function (sort a list using a "natural order" algorithm)

Community
  • 1
  • 1
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
0

You'll have to parse that integer from the title manually. This function will do it.

def parse_title_num(title):
   val = 0
   try:
      val = int(title.rsplit('#')[-1])
   except ValueError:
      pass
   return val


 list.sort(key=lambda x: parse_title_num(x['title'])
Kenan Banks
  • 207,056
  • 34
  • 155
  • 173