Using s.sort([cmp[, key[, reverse]]]) to sort a list of objects based on a attribute

C

cjt22

Hi there

I am fairly new to Python and have not really used regular expressions
before (I think this might be needed for my query) and wondered if you
could help

I have a step class and store in a list step instances
A step instance contains variables: name, startTime etc and startTime
is stored as a string %H:%M:%S

What I would like to do is to be able to sort this list of objects
based on the startTime object so that the first item in the list is
the object with the earliest Start time and last item is the object
with the last Start time.

I belive my key has to be = strpTime(step.sTime, "%H:%M:%S")
But don't know how to create the comparison funciton.

Any help on how I can perform this whole operation would be much
appreciated.

Thanks
Chris
 
T

Tim Golden

Hi there

I am fairly new to Python and have not really used regular expressions
before (I think this might be needed for my query) and wondered if you
could help

I have a step class and store in a list step instances
A step instance contains variables: name, startTime etc and startTime
is stored as a string %H:%M:%S

What I would like to do is to be able to sort this list of objects
based on the startTime object so that the first item in the list is
the object with the earliest Start time and last item is the object
with the last Start time.

I belive my key has to be = strpTime(step.sTime, "%H:%M:%S")
But don't know how to create the comparison funciton.

You're going to get a *lot* of answers on this one!

To start the ball rolling...

<code>
import random

class Step:

def __init__ (self, name, startTime):
self.name = name
self.startTime = startTime

def __cmp__ (self, other):
return cmp (self.startTime, other.startTime)

def __str__ (self):
return str (self.startTime)
__repr__ = __str__

steps = [Step (h, "%02d:00:00" % h) for h in range (10)]
random.shuffle (steps)
print "Shuffled:", steps

steps.sort ()
print "Sorted:", steps
</code>

In this case, I've given the class a ordering-semantic based
on its startTime attribute. Obviously, this only makes sense
if you *always* want your class to sort this way, rather than
in this one instance.

To do it on a per-sort basis, you *could* create simple per-sort
equivalent:

<code fragment>

def compare_by_startTime (one, other):
return cmp (one.startTime, other.startTime)

steps.sort (cmp=compare_by_startTime)

</code>

or, in the case you're asking about, you could use the
operator module's attrgetter function to do what you want:

<code fragment>
import operator

steps.sort (key=operator.attrgetter ("startTime"))

</code>

TJG
 
S

Stefan Arentz

Hi there

I am fairly new to Python and have not really used regular expressions
before (I think this might be needed for my query) and wondered if you
could help

I have a step class and store in a list step instances
A step instance contains variables: name, startTime etc and startTime
is stored as a string %H:%M:%S

What I would like to do is to be able to sort this list of objects
based on the startTime object so that the first item in the list is
the object with the earliest Start time and last item is the object
with the last Start time.

I belive my key has to be = strpTime(step.sTime, "%H:%M:%S")
But don't know how to create the comparison funciton.

Any help on how I can perform this whole operation would be much
appreciated.

Code:

class Step(object):
def __init__(self, time):
self.time = time
def __repr__(self):
return "<Step time=%s>" % self.time

steps = [Step("03:23:23"), Step("12:59:12"), Step("02:32:17")]
print steps

steps.sort(key = lambda s: s.time)
print steps

Output:

[<Step time=03:23:23>, <Step time=12:59:12>, <Step time=02:32:17>]
[<Step time=02:32:17>, <Step time=03:23:23>, <Step time=12:59:12>]

If the default sort order of a Step is always it's time then you can
also define a __cmp__ method like this:

class Step(object):
def __cmp__(self, other):
return cmp(self.time, other.time)

And simply do a steps.sort()

S.
 
M

Marc 'BlackJack' Rintsch

I have a step class and store in a list step instances
A step instance contains variables: name, startTime etc and startTime
is stored as a string %H:%M:%S

What I would like to do is to be able to sort this list of objects
based on the startTime object so that the first item in the list is
the object with the earliest Start time and last item is the object
with the last Start time.

I belive my key has to be = strpTime(step.sTime, "%H:%M:%S")
But don't know how to create the comparison funciton.

Any help on how I can perform this whole operation would be much
appreciated.

This should be enough::

steps.sort(key=lambda s: s.startTime)

If you sort strings of the form 'hh:mm:ss' the represented times are
sorted chronological. No need to convert them to a number first.

If the "natural" sort criterion for `Step` objects is the start time you
might override `__cmp__()` of `Step`\s instead::

def __cmp__(self, other):
return cmp(self.startTime, other.startTime)

Now you can just sort the list with ``steps.sort()``.

Ciao,
Marc 'BlackJack' Rintsch
 
M

Miki

steps.sort(key = lambda s: s.time)
This is why attrgetter in the operator module was invented.
from operator import attrgetter
....
steps.sort(key=attrgettr("time"))

HTH,
 
S

Stefan Arentz

Miki said:
This is why attrgetter in the operator module was invented.
from operator import attrgetter
...
steps.sort(key=attrgettr("time"))

Personally I prefer the anonymous function over attrgettr :)

S.
 
A

Alex Martelli

Stefan Arentz said:
Personally I prefer the anonymous function over attrgettr :)

However, Python disagrees with you...:

brain:~ alex$ python -mtimeit -s'from operator import attrgetter;
L=map(complex,xrange(999))' 'sorted(L, key=lambda x:x.real)'
1000 loops, best of 3: 567 usec per loop

brain:~ alex$ python -mtimeit -s'from operator import attrgetter;
L=map(complex,xrange(999))' 'sorted(L, key=attrgetter("real"))'
1000 loops, best of 3: 367 usec per loop

A speed-up of 35% is a pretty clear indicator of what _Python_ "prefers"
in this situation:).


Alex
 
S

Stefan Arentz

However, Python disagrees with you...:

brain:~ alex$ python -mtimeit -s'from operator import attrgetter;
L=map(complex,xrange(999))' 'sorted(L, key=lambda x:x.real)'
1000 loops, best of 3: 567 usec per loop

brain:~ alex$ python -mtimeit -s'from operator import attrgetter;
L=map(complex,xrange(999))' 'sorted(L, key=attrgetter("real"))'
1000 loops, best of 3: 367 usec per loop

A speed-up of 35% is a pretty clear indicator of what _Python_ "prefers"
in this situation:).

I could not care less :)

S.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,739
Latest member
Clint8040

Latest Threads

Top