Fifteen
Fifteen

Reputation: 123

Sorting a list of dictionaries based on the order of values of another list

I'm using python 2.7.3, and I'm trying to sort a list of dictionaries based on the order of values of another list.

IE:

listOne = ['hazel', 'blue', 'green', 'brown']
listTwo = [{'name': 'Steve', 'eyecolor': 'hazel', 'height': '5 ft. 11 inches'},
           {'name': 'Mark', 'eyecolor': 'brown', 'height': '6 ft. 2 inches'},
           {'name': 'Mike', 'eyecolor': 'blue', 'height': '6 ft. 0 inches'},
           {'name': 'Ryan', 'eyecolor': 'brown', 'height': '6 ft, 0 inches'},
           {'name': 'Amy', 'eyecolor': 'green', 'height': '5 ft, 6 inches'}]

Sorting listTwo based off of the order of values in listOne, we would end up with the following:

print listTwo
[{'name': 'Steve', 'eyecolor': 'hazel', 'height': '5 ft. 11 inches'},
{'name': 'Mike', 'eyecolor': 'blue', 'height': '6 ft. 0 inches'},
{'name': 'Amy', 'eyecolor': 'green', 'height': '5 ft, 6 inches'},
{'name': 'Mark', 'eyecolor': 'brown', 'height': '6 ft. 2 inches'},
{'name': 'Ryan', 'eyecolor': 'brown', 'height': '6 ft, 0 inches'}]

I eventually need to output this text, so what I've done to display it correctly (in the correct order) is the following:

for x in xrange(len(listOne)):
    for y in xrange(len(listTwo)):
        if listOne[x] == listTwo[y]["eyecolor"]:
            print "Name: " + str(listTwo[y]["name"]),
            print "Eye Color: " + str(listTwo[y]["eyecolor"]),
            print "Height: " + str(listTwo[y]["height"])

Is there some sort of lambda expression that can be used to make this happen? There has to be a more compact, less complex way of getting it in the order I want.

Upvotes: 12

Views: 3153

Answers (2)

Allen Jose
Allen Jose

Reputation: 51

listOne = ['hazel', 'blue', 'green', 'brown', 'brown1']
listTwo = [
    {'name': 'Steve', 'eyecolor': 'hazel', 'height': '5 ft. 11 inches'
     },
    {'name': 'Mark', 'eyecolor': 'brown', 'height': '6 ft. 2 inches'},
    {'name': 'Mike', 'eyecolor': 'blue', 'height': '6 ft. 0 inches'},
    {'name': 'Ryan', 'eyecolor': 'brown', 'height': '6 ft, 0 inches'},
    {'name': 'Amy', 'eyecolor': 'green', 'height': '5 ft, 6 inches'},
    {'name': 'Amy', 'eyecolor': 'green2', 'height': '5 ft, 6 inches'},
    ]

print sorted(listTwo, key=lambda i: listOne.index(i['eyecolor']))

Working

  1. First we will iterate through the listTwo and fetch the eyecolor value.
  2. Using that eyecolor value, we need to check the index of that value on listOne.
  3. Based on that index, we will sort values.

But their is a chance of ValueError for this code while fetching the index. So we need to handle it.

print sorted(listTwo, key=lambda i: (listOne.index(i['eyecolor'
             ]) if i['eyecolor'] in listOne else len(listOne) + 1))

Upvotes: 0

Blckknght
Blckknght

Reputation: 104712

The simplest way would be to use list.index to generate a sort value for your list of dictionaries:

listTwo.sort(key=lambda x: listOne.index(x["eyecolor"]))

This is a little bit inefficient though, since list.index does a linear search through the eye-color list. If you had many eye colors to check against, it would be slow. A somewhat better approach would build an index dictionary instead:

order_dict = {color: index for index, color in enumerate(listOne)}
listTwo.sort(key=lambda x: order_dict[x["eyecolor"]])

If you don't want to modify listTwo, you can use the built-in sorted function instead of the list.sort method. It returns a sorted copy of the list, rather than sorting in-place.

Upvotes: 15

Related Questions