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!
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!
Short note building on and : their examples illustrate the old Python‑2 style (cmp / cmp) which will work in legacy code, but for modern Python (3.x) prefer key-based sorting or rich comparisons. list.sort() sorts in‑place and sorted() returns a new list; both support a fast single-argument key function (and reverse). (docs.python.org)
Use a key that extracts the dictionary value from your object. This is simple, fast (the key function is applied once per element) and readable:
# sort in-place by a dict value (use .get to avoid KeyError)
my_list.sort(key=lambda o: o.data.get('score', 0), reverse=True)
# multi-key example: sort by country, then by descending score
my_list.sort(key=lambda o: (o.data.get('country',''), -o.data.get('score',0))) The key approach and the stability of Python’s sort make multi-step or tuple keys reliable. (docs.python.org)
If you need to migrate an old cmp-style comparator (like ’s lambda comparator), wrap it with functools.cmp_to_key so it works with Python 3’s key API:
from functools import cmp_to_key
def cmp_by_k(a, b):
return (a.data['k'] > b.data['k']) - (a.data['k'] < b.data['k'])
my_list.sort(key=cmp_to_key(cmp_by_k)) functools.cmp_to_key is intended exactly for that migration scenario. (docs.python.org)
If the objects should know how to compare themselves, implement rich comparisons (at least lt and eq) or use functools.total_ordering to auto-fill the rest — then plain my_list.sort() will work. Also watch for CSV quirks: DictReader yields strings, so convert numeric fields (int/float) or normalize types inside the key to avoid lexicographic surprises. (docs.python.org)
Jump to Post— jice 53Could 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
Jump to Post— jlm699 320Hi!
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. …
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] 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)) We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.