Hi!

I have a list of class objects, each object contrains a dictionary. Is it possible to sort my list based on a value within each object's dictionary? Can I use the list.sort() method to do this?

Thx!

Could you post some code or be more precise ?
Is this list made of objects from the same class ?
Maybe should you implement the __cmp__ OR __eq__, __ge__, __gt__, __le__, __lt__ and __ne__ special method in your object... That would allow comparisons between objects. and sort them

Hi!

I have a list of class objects, each object contrains a dictionary. Is it possible to sort my list based on a value within each object's dictionary? Can I use the list.sort() method to do this?

Thx!

Yes. You'll need to use the function parameter of the sort method. Here's an example of sorting a list of objects by a particular variable. This method makes use of a lambda function

>>> class C(object):
...     def __init__(self, inp):
...         self.data = inp
...     
>>> my_list = []
>>> for ch in 'hbracdfeniklj':
...     my_list.append(C(ch))
...     
>>> for elem in my_list:
...     print elem.data
...     
h
b
r
a
c
d
f
e
n
i
k
l
j
>>> my_list.sort(lambda x,y: cmp(x.data,y.data))
>>> for elem in my_list:
...     print elem.data
...     
a
b
c
d
e
f
h
i
j
k
l
n
r
>>>

As you can see the sort function compares two elements at a time, so in my lambda function I take x and y as inputs. The cmp function similarly takes two inputs and returns -1 if x<y, 0 if x==y, and 1 if x>y; which just so happen to be the values that the sort function is looking for when sorting by comparison.

Hope that helps in your specific case. If you need some more specific advice, we'll need some more specific info!

Maybe is jlm699's solution simpler but i'll just put an example of what I said yesterday (I had no time to do it yesterday) as it is interesting anyway because it allows comparisons between objects in any situation (if objectA > objectB: )
note that __repr__ (as we are in special methods) allows to print the object the way you want...

class myobject:
    def __init__(self, c):
        self.c=c

    def __cmp__(self, alien):
        if self.c < alien.c:
            return -1
        elif self.c == alien.c:
            return 0
        else:
            return 1

    def __repr__(self):
        return str(self.c)

l=[]
for character in "akljdfliouerjslk":
    l.append(myobject(character))
print l
>> [a, k, l, j, d, f, l, i, o, u, e, r, j, s, l, k]
l.sort()
print l
>> [a, d, e, f, i, j, j, k, k, l, l, l, o, r, s, u]

Edited 7 Years Ago by jice: n/a

Maybe is jlm699's solution simpler but i'll just put an example of what I said yesterday (I had no time to do it yesterday) as it is interesting anyway because it allows comparisons between objects in any situation (if objectA > objectB: )
note that __repr__ (as we are in special methods) allows to print the object the way you want...

class myobject:
    def __init__(self, c):
        self.c=c

    def __cmp__(self, alien):
        if self.c < alien.c:
            return -1
        elif self.c == alien.c:
            return 0
        else:
            return 1

    def __repr__(self):
        return str(self.c)

l=[]
for character in "akljdfliouerjslk":
    l.append(myobject(character))
print l
>> [a, k, l, j, d, f, l, i, o, u, e, r, j, s, l, k]
l.sort()
print l
>> [a, d, e, f, i, j, j, k, k, l, l, l, o, r, s, u]

Jice, our solutions are almost one in the same. In your example, you've overloaded the class __cmp__ function. It is a good demonstration to the OP as a beginner (to demonstrate how a custom-rolled cmp function could be written); however your example could be simplified by just specifying which element of the object needs to be "cmp"ed. Like so:

>>> class myobject:
...     def __init__(self, c):
...         self.c = c
...     def __cmp__(self, alien):
...         return cmp(self.c, alien.c)
...     def __repr__(self):
...         return str(self.c)
...     
>>> l = []
>>> for character in "akljdfliouerjslk":
...     l.append(myobject(character))
...     
>>> print l
[a, k, l, j, d, f, l, i, o, u, e, r, j, s, l, k]
>>> l.sort()
>>> print l
[a, d, e, f, i, j, j, k, k, l, l, l, o, r, s, u]
>>>

As you can see, our two solutions are very similar. The advantage in this case would be to your solution, as the user wouldn't have to redefine the cmp function each time they call sort (as in my example).

You're right... No need to re-invent the wheel.
The fact is that i've never used these functions (cmp, __cmp__ or whatever)... So I didn't think of it.
BUT, to save my honor and not commit seppuku, i'd add that the detailed function i wrote shows the principle of a __cmp__ function. You can test whatever you want (not only one field of each objet) and if __cmp__ returns -1, 0 and 1, you will be able to compare differents objects, sort() lists of them and so on. Simple, clean. Pythonic

Python is so clean and easy...
I'm writing some php code these days and I find it so heavy in comparison.

I'm reading a CSV with dictReader then assigning each dictionary to an object. I used your input to sort my objects based on certain dictionary keys and it worked a treat! So many thx for introducing me to __cmp__. I'm not completely sure why __repr__ in useful here though, is it still required as I'm only comparing strings.

thx again!

__repr__ is not required as you are only sorting your objects.
I put it here just to introduce this way of printing objects.
If you have a complex object with some interesting fields to display, defining __repr__ will be an easy and clean way to do this.
Instead of doing

print "%s - %s" % (str(myobject.data1), str(myobject.data2))

each time i want to print the object useful datas, I just have to do

print myobject
# if __repr__ is defined and returns "%s - %s" % (str(self.data1), str(self.data2))

Edited 7 Years Ago by jice: n/a

This article has been dead for over six months. Start a new discussion instead.