Antoine
Antoine

Reputation: 57

Removing duplicates in lists of objects keeping the max and the order

I have a list of dict and i want to remove all objects with an equal x value keeping the y max value and the list order. I made the following code:

#!/usr/bin/python3

from pprint import pprint
import operator

lst = [{'x': 207, 'y': 40}, {'x': 207, 'y': 45}, {'x': 254, 'y': 62}, {'x': 260, 'y': 26}, {'x': 351, 'y': 71}, {'x': 351, 'y': 5},  {'x': 351, 'y': 15},  {'x': 391, 'y': 24},  {'x': 391, 'y': 48}]

pprint(lst)
[{'x': 207, 'y': 40},
 {'x': 207, 'y': 45},
 {'x': 254, 'y': 62},
 {'x': 260, 'y': 26},
 {'x': 351, 'y': 71},
 {'x': 351, 'y': 5},
 {'x': 351, 'y': 15},
 {'x': 391, 'y': 24},
 {'x': 391, 'y': 48}]

copy = []
[
    copy.append(max(
        (point2 for point2 in lst if point["x"] == point2["x"]),
        key=operator.itemgetter('y'))
    )
    for point in lst
        if next(
            (cPoint for cPoint in copy if cPoint['x'] == point['x']),
            None) == None
]

pprint(copy)
[{'x': 207, 'y': 45},
 {'x': 254, 'y': 62},
 {'x': 260, 'y': 26},
 {'x': 351, 'y': 71},
 {'x': 391, 'y': 48}]

I'm just asking if there is a more elegant (and Pythonic) way to do this?

Thanks in advance

Upvotes: 2

Views: 1060

Answers (2)

Carsten
Carsten

Reputation: 18446

In addition to tobias_k's answer, here is one in a more functional style. First, we group all elements of lst by their x value, then, for each group, we get the one with the largest y. Afterwards, we can just go though all elements of lst and check if it's inside the list of maxima. If it is, put it into copy:

import itertools

getx, gety = lambda a: a['x'], lambda a: a['y'] # or use operator.itemgetter
groups = itertools.groupby(sorted(lst, key=getx), key=getx)
m = [max(b, key=gety) for a,b in groups]
copy = [l for l in lst if l in m]

Upvotes: 2

tobias_k
tobias_k

Reputation: 82899

How about this: First create a dictionary holding the maximum y value for each x, then keep those values from the list that have that highest y value for their respective x.

maxima = {}
for d in lst:
    x, y = d["x"], d["y"]
    if x not in maxima or y > maxima[x]:
        maxima[x] = y
copy = [d for d in lst if d["y"] == maxima[d["x"]]]

Upvotes: 2

Related Questions