Sardorbek Imomaliev Sardorbek Imomaliev - 1 year ago 46
Python Question

Filter list of dicts by higest value of dict and taking reversed values into account

Let's say i have data looking like this:

filter_data = [
{'sender_id': 1, 'receiver_id': 2, 'order': 1},
{'sender_id': 2, 'receiver_id': 1, 'order': 3},
{'sender_id': 3, 'receiver_id': 2, 'order': 5},
{'sender_id': 2, 'receiver_id': 3, 'order': 2},

# there must be a better way to get max elements by reversed keys
# in list of dicts, but I think this whole another question
# so for now let this be this way.
def get_data():
qs_data = []
for data in filter_data:
for cmp_data in filter_data:
if data['sender_id'] == cmp_data['receiver_id'] and\
data['receiver_id'] == cmp_data['sender_id']:
if data['order'] > cmp_data['order']:
d = data
d = cmp_data
if d not in qs_data:
return qs_data

and desired output will be

[{'order': 3, 'receiver_id': 1, 'sender_id': 2},
{'order': 5, 'receiver_id': 2, 'sender_id': 3}]

What my code does it filters
so I will get list of items with highest value of
but for me
receiver_id=1, sender_id=2
is same as
sender_id=1, receiver_id=2

So my question is is there more pythonic/faster way to do this? Or may be can someone point to direction of improvement.

P.S. I would appreciate if someone can come up with understandable title. Sorry for my bad English.

Answer Source

You can use a dictionary, mapping a frozenset of sender and receiver ID (so order does not matter) to the item with the currently highest order.

result = {}
for item in filter_data:
    key = frozenset([item["sender_id"], item["receiver_id"]])
    if key not in result or result[key]["order"] < item["order"]:
        result[key] = item

Then, just extract the values() from the dictionary to get [{'order': 3, 'receiver_id': 1, 'sender_id': 2}, {'order': 5, 'receiver_id': 2, 'sender_id': 3}]

Or collect all the items, grouped by sender/receiver pair, and use a list comprehension with max to get those with the highest orders:

result = collections.defaultdict(list)
for item in filter_data:
    key = frozenset([item["sender_id"], item["receiver_id"]])
max_values = [max(lst, key=lambda x: x["order"]) for lst in result.values()]