tags:

views:

61

answers:

3

I have two instances of an object in a list

class Thing():
     timeTo = 0
     timeFrom = 0
     name = ""

o1 = Thing()
o1.name = "One"
o1.timeFrom = 2

o2 = Thing()
o2.timeTo = 20
o2.name = "Two"

myList = [o1, o2]


biggestIndex = (myList[0].timeFrom < myList[1].timeTo) & 1
bigger  = myList.pop(biggestIndex)
lesser  = myList.pop()

print bigger.name
print lesser.name

both o1 and o2 have two properties that I want to compare the first in the lists timeFrom property and the second ones timeTo property to eachother.

I feel this is a bit awkward and wierd, is there perhaps a better and more readable approach to this?

+1  A: 

see attrgetter

import operator

getter = operator.attrgetter('timeFrom')

bigger = max(myList, key=getter)  
lesser = min(myList, key=getter)

print bigger.name  
print lesser.name

EDIT :

attrgetter also wokrs with sorted or anywhere a key function is needed.

lesser, bigger = sorted(myList, key=getter)
dugres
+1, `operator.attrgetter` is definitely the right approach (but **please** edit this A to do it right: start with `import operator` and use `operator.attrgetter` explicitly -- doing otherwise is not only debatable style, but _sure_ to leave beginners terribly perplexed as Python gives them a "name not found" error!!!).
Alex Martelli
The OP wants to sort by comparing *two attributes* so this cannot work (and it doesn't give the right result).
THC4k
as THC4k said, I need to compare one attribute to another attribute, is there a way to make this fit my need of comparing one attibute to another?
Joelbitar
@alex : done. @THC4k and @Joelbitar : see EDIT
dugres
+2  A: 

The best solution is to make Thing instances sortable. You do this by implementing __lt__:

class Thing():
     timeTo = 0
     timeFrom = 0
     name = ""

     def __lt__(self, other):
         return self.timeFrom < other.timeTo


lesser, bigger = sorted(myList)

Python2 has lesser, bigger = sorted(myList, cmp=lambda one,other: one.timeFrom < other.timeTo).

In Python3 cmp is gone, I guess to force people to do (or learn) OOP and write a adapter.

class SortAdaper(object):
    def __init__(self, obj ):
        self.obj = obj

class TimeLineSorter(SortAdaper):
    """ sorts in a timeline """
    def __lt__(self, other):
        return self.obj.timeFrom < other.obj.timeTo

class NameSorter(SortAdaper):
    """ sorts by name """
    def __lt__(self, other):
        return self.obj.name < other.obj.name

print sorted( myList, key=TimeLineSorter)
print sorted( myList, key=NameSorter)
THC4k
@Justin Ardini: That's a property of the metric the OP defined. o1 and o2 are simply not sortable in this case.
THC4k
When you have `o1.timeFrom >= o2.timeTo` and `o2.timeFrom >= o1.timeTo` and you want that `o1.timeFrom <= o1.timeTo` ( which is very reasonable given the variable names ) then this implies (do the math!) that `o2.timeFrom >= o2.timeTo` ... and that makes no sense!
THC4k
Perfect! I ended up writing a sorter and using it as key argument to the sorted function, thank you!
Joelbitar
A: 

I would do this, if object can have only one of the time values:

class Thing(object):
    def __init__(self, name, time = 0, timename = 'to'):
        self.name, self.time, self.timename = (name,time,timename)

    def __repr__(self):
        return "Thing(%r, %i, %r)" % (self.name, self.time, self.timename)

    def __lt__(self, other):
        return self.time < other.time

o1 = Thing("One", 5, 'from')

o2 = Thing("Two", 20, 'to')

myList = [o1, o2]

print myList
print max(myList)
print min(myList)
Tony Veijalainen