Tanishq dubey
Tanishq dubey

Reputation: 1542

Python custom sort function for strings like 'Season Year'

I have a list of the form 'Season Year':

['Fall 2014', 'Spring 2015', 'Fall 2008', 'Spring 2008']

And when sorted, the list should look like this:

['Spring 2015', 'Fall 2014', 'Spring 2008', 'Fall 2008']

Hence, the rules for sorting are:

  1. First sort by year

  2. Sort by season: 'Spring' then 'Fall'

I currently have a function called lcmp that I use on my list like this: myList.sort(lcmp).

>>> def lcmp(a,b):
...     c = a.split()
...     d = b.split()
...     if(c[1]>d[1]):
...             if(c[0]>d[0]):
...                     return 1
...             else:
...                     return -1
...     else:
...             if(c[0]>d[0]):
...                     return 1
...             else:
...                     return 0
... 

This works for sorting by year, but does not work for the season, even though I have specified that type of sorting. Why is this happening?

Upvotes: 9

Views: 1750

Answers (3)

JuniorCompressor
JuniorCompressor

Reputation: 20025

One of the errors is that you don't check correctly for equality. What you return when c[1] < d[1] and c[0] < d[0]? The answer is zero, which is incorrect. Also you should declare cmp argument in sort. What you can do is the following:

seasons = {
    'Spring': 1,
    'Summer': 2,
    'Fall': 3,
    'Winter': 4,
}
def lcmp(a, b):
    a_season, a_year = a.split()
    b_season, b_year = b.split()
    return int(b_year) - int(a_year) or seasons[a_season] - seasons[b_season]

l = ['Fall 2014', 'Spring 2015', 'Fall 2008', 'Spring 2008']
l.sort(cmp=lcmp)

Result:

['Spring 2015', 'Fall 2014', 'Spring 2008', 'Fall 2008']

And if you want to play with iterators:

from itertools import ifilter, izip

def lcmp(a, b):
    it = (
        f(y) - f(x)
        for x, y, f in izip(
            reversed(a.split()),
            reversed(b.split()),
            (int, lambda _: -seasons[_])
        )
    )
    return next(ifilter(None, it), 0)

Upvotes: 2

Padraic Cunningham
Padraic Cunningham

Reputation: 180481

Just using -year to reverse the sort by year as the first key and the result of seas != "Spring" to break the ties using key=sort_function.

l = ['Fall 2014', 'Spring 2015', 'Fall 2008', 'Spring 2008']
def key(x):
    seas,year = x.split()
    return -int(year), seas != "Spring"

l.sort(key=key)

There is no way your function will work even if you use myList.sort(key=lcmp) as you are passing single strings so you don't have a and b to split. This will also work for python 2 or 3.

Upvotes: 5

Simeon Visser
Simeon Visser

Reputation: 122466

You should also take into account the cases where the compared values are equal:

def lcmp(a,b):
    c = a.split()
    d = b.split()
    if c[1] > d[1]:
        return 1
    elif c[1] == d[1]:
        if c[0] > d[0]:
            return -1
        elif c[0] == d[0]:
            return 0
        else:
            return 1
    else:
        return -1

You can then sort the data using myList.sort(lcmp) or myList.sort(cmp=lcmp)

Upvotes: 0

Related Questions