按dict的最高值过滤dicts列表并将反转值考虑在内

时间:2016-09-01 09:19:41

标签: python

我们说我的数据看起来像这样:

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
                else:
                    d = cmp_data
                if d not in qs_data:
                    qs_data.append(d)
    return qs_data

并且所需的输出将是

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

我的代码会过滤filter_data,因此我会获得ordersender_id receiver_id值最高的项目列表,但对我来说receiver_id=1, sender_id=2sender_id=1, receiver_id=2

相同

所以我的问题是有更多pythonic /更快的方法吗?或者可能有人指出改进的方向。

P.S。如果有人能提出可以理解的头衔,我将非常感激。抱歉我的英语不好。

3 个答案:

答案 0 :(得分:1)

您可以使用字典,将frozenset发件人和收件人ID(因此顺序无关紧要)映射到当前最高顺序的项目。

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

然后,只需从字典中提取values()即可获得[{'order': 3, 'receiver_id': 1, 'sender_id': 2}, {'order': 5, 'receiver_id': 2, 'sender_id': 3}]

或收集按发件人/收件人对分组的所有商品,并使用max的列表理解来获得订单最高的商品:

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

答案 1 :(得分:1)

我现在理解你了吗?

from itertools import groupby

grp = groupby(filter_data, lambda x: (min(x["sender_id"], x["receiver_id"]), max(x["sender_id"], x["receiver_id"])))
l = [sorted(g, key = lambda x: -x["order"])[0] for k, g in grp]

答案 2 :(得分:0)

创建一个空字典,收集新的最高字典。我们遍历您的filter_data并查看sender_idreceiver_id的总和,因为您说这些顺序无关紧要。

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},
]

new = {}
for d in filter_data:
    total = d['sender_id'] + d['receiver_id']
    if total in new:
        if d['order'] > new[total]['order']:
            new[total] = d
    else:
        new[total] = d

print new.values()

例如,它将浏览第一个字典并评估其receiver_idsender_id的总和(总和为3)。由于我们还没有遇到sender_idreceiver_id添加最多3的字典,因此它会被添加到我们的新字典中。

但是,下一个字典的总和也是3.我们检查它的order值是否大于前一个字典。既然如此,它就会覆盖以前的字典。

然后我们打印新词典的值,因为键只包含sender_idreceiver_id的总和。