Ronzo
Ronzo

Reputation: 97

Sort a dictionary by values that are instance attributes

I am currently working on a program written in Python 2.6.6. It uses a dictionary that looks like:

{ 'somekeystring': someobject("a name", 1, 3),
'anotherkey': someobject("another name", 2, 2),
'keythree': someobject("third name", 3, 1) }

The object has some attributes like:

name
startOrder
stopOrder

What I am trying to accomplish is to get the dictionary sorted. Once by someobject.startOrder, once by someobject.stopOrder.

I have tried

sortedByStartOrder = sorted(mydict.iteritems(), key=lambda x: x[1].startOrder)

but this does not seem to work. The list items are sorted in the same order, no matter if I use startOrder or stopOrder in the example above.

Any hints?

Upvotes: 1

Views: 83

Answers (3)

Ronzo
Ronzo

Reputation: 97

Thanks a lot for all your input! I wrote a simple example like Odexios' and it worked perfectly with

sortedByStartOrder = sorted(mydict.iteritems(), key=lambda x: x[1].startOrder)

The clue was:

I'd guess the problem isn't in the sort itself; there might be something wrong in the structures you're trying to sort.

I went through my code and found a code passage where I set both variables to 0.

Upvotes: 1

logc
logc

Reputation: 3923

You can define your own comparing function that is given to the sorted builtin in the keyword cmp.

def sort_by_start(obj1, obj2):
    # this is just an example using '>' and '<' as comparison operators
    # you can compare 1 and 2 using whatever methods you wish; just
    # return a negative number if 1 is less than 2, 0 if they are equal
    # or a positive number if 1 is greater than 2.
    if obj1.startOrder < obj2.startOrder:
        return -1
    if obj1.startOrder > obj2.startOrder:
        return 1
    else:
        return 0

sorted(mydict.iteritems(), cmp=sort_by_start, key=lambda x: x[1])

def sort_by_stop(obj1, obj2):
    # let's make this more specific: imagine `stopOrder` is a string,
    # but we need to remove a prefix before we sort them alphabetically
    common_prefix = 'id-'  # or whatever
    comp1 = obj1.stopOrder.lstrip(common_prefix)
    comp2 = obj2.stopOrder.lstrip(common_prefix)
    if comp1 < comp2:
        return -1
    if comp1 > comp2:
        return 1
    else:
        return 0

sorted(mydict.iteritems(), cmp=sort_by_stop, key=lambda x: x[1])

Upvotes: 0

gcali
gcali

Reputation: 1248

This example seems to work for me:

class P:
    def __init__(self, x):
        self.x = x

d = { 'how': P(3), 'hi': P(2), 'you': P(5), 'are': P(4) }
print list(d.iteritems())
print sorted(d.iteritems(), key=lambda x: x[1].x)

produces

>> [('how', <__main__.P instance at 0x7f92028e52d8>), ('you', <__main__.P instance at 0x7f92028e5368>), ('hi', <__main__.P instance at 0x7f92028e5320>), ('are', <__main__.P instance at 0x7f92028e53b0>)]
>> [('hi', <__main__.P instance at 0x7fc210e6c320>), ('how', <__main__.P instance at 0x7fc210e6c2d8>), ('are', <__main__.P instance at 0x7fc210e6c3b0>), ('you', <__main__.P instance at 0x7fc210e6c368>)]

I'd guess the problem isn't in the sort itself; there might be something wrong in the structures you're trying to sort.

Upvotes: 1

Related Questions