Newbie: sort list of dictionaries

S

Sven Brandt

Hi there,

please excuse for asking such basic questions (I am new to programming, esp.
python).

I have a list of dictionaries. I want the elements of the list to be sorted by
the value of a key of the dict .

Excample:
my_list=[{'title': 'foo', 'id': 5, 'text': 'some text'},
{'title': 'bar', 'id': 3, 'text': 'my text'},
{'title': 'bla', 'id': 6, 'text': 'any text'}, ]

my_list.sort("by the id value")

Thanx for help
Sven
 
P

Paul Rubin

Sven Brandt said:
I have a list of dictionaries. I want the elements of the list to be
sorted by the value of a key of the dict .

Excample:
my_list=[{'title': 'foo', 'id': 5, 'text': 'some text'},
{'title': 'bar', 'id': 3, 'text': 'my text'},
{'title': 'bla', 'id': 6, 'text': 'any text'}, ]

my_list.sort("by the id value")

The Pythonic way to do it may not be what you're used to, but once you
understand it you'll be able to apply the understanding to other areas
of programming.

The list sort method lets you pass an optional comparison function,
that takes two items and returns -1, 0, or 1, depending on what order
the items are supposed to appear in. The comparison function takes
exactly two args (the items to be compared). You can't pass a third
arg to specify the field name. You could do something ugly like use a
global variable, but the preferred way given a field name is to
construct a brand new comparison function just for that name:

def compare_by (fieldname):
def compare_two_dicts (a, b):
return cmp(a[fieldname], b[fieldname])
return compare_two_dicts

What's that? Two nested function definitions. The outer function,
compare_by, creates a new function called compare_two_dicts, which
compares specifically based on the field that you passed to the outer
function. compare_by then returns the new function, that's right,
functions are values in Python! You can then can pass the new
function to the sort method:

my_list.sort (compare_by ('id'))

And my_list is then properly sorted:

[{'text': 'my text', 'id': 3, 'title': 'bar'},
{'text': 'some text', 'id': 5, 'title': 'foo'},
{'text': 'any text', 'id': 6, 'title': 'bla'}]
 
S

Sven Brandt

Hi Paul,

thanks a lot, esp. for the good explanation. That's excactly what i needed.

Regards
Sven
 
W

Wade Leftwich

Paul Rubin said:
Sven Brandt said:
I have a list of dictionaries. I want the elements of the list to be
sorted by the value of a key of the dict .

Excample:
my_list=[{'title': 'foo', 'id': 5, 'text': 'some text'},
{'title': 'bar', 'id': 3, 'text': 'my text'},
{'title': 'bla', 'id': 6, 'text': 'any text'}, ]

my_list.sort("by the id value")

The Pythonic way to do it may not be what you're used to, but once you
understand it you'll be able to apply the understanding to other areas
of programming.

The list sort method lets you pass an optional comparison function,
that takes two items and returns -1, 0, or 1, depending on what order
the items are supposed to appear in. The comparison function takes
exactly two args (the items to be compared). You can't pass a third
arg to specify the field name. You could do something ugly like use a
global variable, but the preferred way given a field name is to
construct a brand new comparison function just for that name:

def compare_by (fieldname):
def compare_two_dicts (a, b):
return cmp(a[fieldname], b[fieldname])
return compare_two_dicts
[snip ...]

Another way to do it, also Pythonic I think, is with the
Decorate-Sort-Undecorate (DSU) pattern:

unsorted_list = [{'id':99, 'title':'a'},{'id':42, 'title':'b'}, ... ]
decorated_list = [(x['id'],x) for x in unsorted_list]
decorated_list.sort()
sorted_list = [y for (x,y) in decorated_list]

If performance is a consideration, this is supposed to be much faster
than providing a comparison function to list.sort().

If you want to package it up as a function, try this:
.... if decorator is None:
.... def decorator(x):
.... return x
.... newL = [(decorator(x), x) for x in L]
.... newL.sort()
.... L[:] = [y for (x,y) in newL]
....
L = [2,3,6,1,17,0]
sortlist(L)
L [0, 1, 2, 3, 6, 17]
L = [{'id':99, 'title':'a'},{'id':42, 'title':'b'}]
def mydecorator(mydict):
.... return mydict['id']
....
sortlist(L, mydecorator)
L [{'id': 42, 'title': 'b'}, {'id': 99, 'title': 'a'}]

Now you have in-place sorting, just like with the built-in sort()
method.

-- Wade Leftwich
Ithaca, NY
 
W

Wade Leftwich

D'oh! That sortlist() function was needlessly clever. This is nicer:
.... if decorator is None:
.... L.sort()
.... return
.... newL = [(decorator(x), x) for x in L]
.... newL.sort()
.... L[:] = [y for (x,y) in newL]
 
P

Paul Rubin

D'oh! That sortlist() function was needlessly clever. This is nicer:
... if decorator is None:
... L.sort()
... return
... newL = [(decorator(x), x) for x in L]
... newL.sort()
... L[:] = [y for (x,y) in newL]

Ugh! And don't forget that you still have to write the parametrized
decorator function which is missing there. It's simpler in this
example to use use a tailored comparison function than to mess with
that DSU approach.
 
R

Raymond Hettinger

[Sven Brandt]
I have a list of dictionaries. I want the elements of the list to be
sorted by the value of a key of the dict .

Excample:
my_list=[{'title': 'foo', 'id': 5, 'text': 'some text'},
{'title': 'bar', 'id': 3, 'text': 'my text'},
{'title': 'bla', 'id': 6, 'text': 'any text'}, ]

my_list.sort("by the id value")

[Paul Rubin]
The Pythonic way to do it may not be what you're used to, but once you
understand it you'll be able to apply the understanding to other areas
of programming.

The list sort method lets you pass an optional comparison function,
that takes two items and returns -1, 0, or 1, depending on what order
the items are supposed to appear in. The comparison function takes
exactly two args (the items to be compared). You can't pass a third
arg to specify the field name. You could do something ugly like use a
global variable, but the preferred way given a field name is to
construct a brand new comparison function just for that name:

def compare_by (fieldname):
def compare_two_dicts (a, b):
return cmp(a[fieldname], b[fieldname])
return compare_two_dicts

[Wade Leftwich]
Another way to do it, also Pythonic I think, is with the
Decorate-Sort-Undecorate (DSU) pattern:

unsorted_list = [{'id':99, 'title':'a'},{'id':42, 'title':'b'}, ... ]
decorated_list = [(x['id'],x) for x in unsorted_list]
decorated_list.sort()
sorted_list = [y for (x,y) in decorated_list]

If performance is a consideration, this is supposed to be much faster
than providing a comparison function to list.sort().

FWIW, direct support for DSU is built into Py2.4:
[{'text': 'any text', 'id': 6, 'title': 'bla'}, {'text': 'my text',
'id': 3, 'title': 'bar'}, {'text': 'some text', 'id': 5, 'title':
'foo'}]


Raymond Hettinger
 

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
474,174
Messages
2,570,940
Members
47,485
Latest member
Andrewayne909

Latest Threads

Top