[Tutor] Question about sorting a list within a dictionary within a list

Peter Otten __peter__ at web.de
Mon Aug 1 22:03:18 CEST 2011


ian douglas wrote:

> I'm using the Bono library for talking to EC2, and I'm getting a list of
> EC2 instances back in a list called "reservations". Each element in the
> list is a dictionary of information. One of those dictionary elements is
> a list called 'instances', and I only ever care about the first entry.
> That instances[0] value is a dictionary, which holds a key I want to use
> to sort the base "reservations" list.
> 
> I found this helpful bit for sorting a list of dictionaries by a key
> within the dictionaries:
> http://stackoverflow.com/questions/72899/in-python-how-do-i-sort-a-list-
of-dictionaries-by-values-of-the-dictionary
> 
> ... this works great if you just have a list of dictionaries. I'm not
> sure how to go deeper within that to sort my data without iterating
> through the entire 'reservations' list and building an entirely new
> list. Maybe it would be easier, but I'm just curious if it's possible
> without messing with my main 'reservations' list.
> 
> 
> My current code looks like this: (it's a views.py file)
> 
> from django.http import HttpResponse
> import boto.ec2
> from operator import itemgetter
> 
> def index(request):
>      conn = boto.connect_ec2()
>      reservations = conn.get_all_instances()
> 
>      # this is where I'm trying to sort everything
>      res_sorted = sorted(reservations, key=itemgetter('launch_time'))
> 
>      output = '<table>'
>      output += '<tr>'
>      output += '<th>State</th>'
>      output += '<th>Launched</th>'
>      output += '<th>Public Hostname</th>'
>      output += '<th>Public IP</th>'
>      output += '<th>Private Hostname</th>'
>      output += '<th>Private IP</th>'
>      output += '</tr>'
>      for reservation in res_sorted:
>          instance = reservation.instances[0]
>          output += '<tr>'
>          output += '<td>' + instance.state + '</td>'
>          output += '<td>' + instance.launch_time + '</td>'
>          output += '<td>' + instance.public_dns_name + '</td>'
>          output += '<td>' + instance.ip_address + '</td>'
>          output += '<td>' + instance.private_dns_name + '</td>'
>          output += '<td>' + instance.private_ip_address + '</td>'
> 
> 
> Ideally, I'd like to make each table column 'sortable' so the user can
> click on state/launched/etc (I may add more columns in the future), but
> I'm not sure how to search deeper within the 'reservations' list for the
> sorted() call to get at the 'launch_time' element within the instaces[0]
> dictionary.
> 
> Also, I'm sure there are much better ways to do the display logic, but
> I'll tackle that another time.

I cannot help you with the django or boto part. As to sorting lists: to do 
it inplace invoke the sort() method:

reservations.sort(key=mykey)

You can think of itemgetter("launch_time") as a function that creates the 
the following function on the fly:

def mykey(item):
    return item["launch_time"]

Judging from the code you provide you need

def mykey(item):
    return item.instances[0].launch_time

instead. If you want to be flexible about the actual attribute you can 
change that to

attrname = ...
def mykey(item):
    return getattr(item.instances[0], attrname)

Djange probably offers a way to provide the desired attribute name via the 
request object. Your index() function would then become

LEGAL_SORTKEYS = set(["launch_time", "ip_address"])

def index(request):
    conn = boto.connect_ec2()
    reservations = conn.get_all_instances()
    attrname = ... # your code
    if attrname in LEGAL_SORTKEYS:
        def mykey(item):
            return getattr(item.instances[0], attrname)
        reservations.sort(key=mykey)
    else:
        ... # provide an error message or just don't sort

    output = '<table>'
    output += '<tr>'
    ...




More information about the Tutor mailing list