Kumba
Kumba

Reputation: 2428

Sorted/unique list of object instances from a larger list?

I have a list of object instances that I want to sort/uniqueify into a new list. Each object implements a variety of properties, but the three properties of importance are a, b, and c. All three properties return an integer value, with a and b sorted low-to-high and c sorted high-to-low.

Example list:

>>> x
>>> [<Foo object at 0x2b371b90>, <Foo object at 0x2b371f38>, <Foo object at 0x2b3719e0>, <Foo object at 0x2b376320>, <Foo object at 0x2b3765f0>]


If I loop and printed the value of a, b, and c in a tuple for each object, they would look like this:

>>> for o in x:
...    print (o.a, o.b, o.c)
...
(2, 78342112, 9)
(2, 78342117, 3)
(2, 78342112, 10)
(2, 78342112, 8)
(2, 78342117, 4)


I've figured out how to sort the list by a/b being low-to-high and c being high-to-low by defining a key() function in the object's class:

def key(self):
    return (self.a, self.b, -self.c)


And passing that to sorted():

x2 = sorted(x, key=lambda x:x.key())
>>> for o in x2:
...    print (o.a, o.b, o.c)
...
(2, 78342112, 10)
(2, 78342112, 9)
(2, 78342112, 8)
(2, 78342117, 4)
(2, 78342117, 3)


For these specific objects, uniqueness between instances depends on if a and b are the same values between two instances. If they are different, then c is never considered, else, we favor the largest value of c. What I'd like to do is generate a new list from either x or x2 in my examples above that only contains one instance for each case when a and b are the same, and retain the one whose c value is largest. The new list, x3, would look like this:

>>> x3 = <magic sorting/unique function called here>
>>> for o in x3:
...    print (o.a, o.b, o.c)
...
(2, 78342112, 10)
(2, 78342117, 4)


I think I can do this using reduce() and a custom function, but the algorithm/logic to do so simply stumps me at the moment.

Ideas?

Upvotes: 2

Views: 123

Answers (1)

NPE
NPE

Reputation: 500673

One way to do this is using itertools.groupby():

import itertools

x3 = [next(g) for k, g in itertools.groupby(x2, lambda x:(x.a, x.b))]

This picks the first element of each group with the same key.

Upvotes: 1

Related Questions