简体   繁体   English

转换字典列表,根据键组合列表项

[英]Transform list of dicts, combining list items based on key

Given a list of dictionaries like:给定一个字典列表,例如:

history = [
  {
    "actions": [{"action": "baz", "people": ["a"]}, {"action": "qux", "people": ["d", "e"]}],
    "events": ["foo"]
  },
  {
    "actions": [{"action": "baz", "people": ["a", "b", "c"]}],
    "events": ["foo", "bar"]
  },
]

What is the most efficient (whilst still readable) way to get a list of dicts, where each dict is an unique event and the list of actions for that event have been merged based on the action key.获取 dicts 列表的最有效(虽然仍然可读)方法是什么,其中每个 dict 是一个唯一event ,并且该事件的操作列表已根据action键合并。 For example, for the above list, the desired output is:例如,对于上面的列表,所需的 output 是:

output = [
    {
      "event": "foo", 
      "actions": [
        {"action": "baz", "people": ["a", "b", "c"]}, 
        {"action": "qux", "people": ["d", "e"]}
      ]
    },
    {
      "event": "bar", 
      "actions": [
        {"action": "baz", "people": ["a", "b", "c"]}
      ]
    },
]

I can't change the output structure as it's being consumed by something external.我无法更改 output 结构,因为它正在被外部事物消耗。 I've wrote the following code which works but is very verbose and has poor readability.我编写了以下代码,该代码有效,但非常冗长且可读性差。

from collections import defaultdict

def transform(history):
    d = defaultdict(list)
    for item in history:
        for event in item["events"]:
            d[event] = d[event] + item["actions"]
    transformed = []
    for event, actions in d.items():
        merged_actions = {}
        for action in actions:
            name = action["action"]
            if merged_actions.get(name):
                merged_actions[name]["people"] = list(set(action["people"]) | set(merged_actions[name]["people"]))
            else:
                merged_actions[name] = {
                    "action": action["action"],
                    "people": action["people"]
                }
        transformed.append({
            "event": event,
            "actions": list(merged_actions.values())
        })
    return transformed

I'm only targeting python3.6+我只针对python3.6+

You can use collections.defaultdict with itertools.groupby :您可以将collections.defaultdictitertools.groupby一起使用:

from collections import defaultdict
from itertools import groupby as gb
d = defaultdict(list)
for i in history:
  for b in i['events']:
    d[b].extend(i['actions'])

new_d = {a:[(j, list(k)) for j, k in gb(sorted(b, key=lambda x:x['action']), key=lambda x:x['action'])] for a, b in d.items()}
result = [{'event':a, 'actions':[{'action':c, 'people':list(set([i for k in b for i in k['people']]))} for c, b in d]} for a, d in new_d.items()]

Output: Output:

[
 {'event': 'foo', 
  'actions': [
     {'action': 'baz', 'people': ['b', 'a', 'c']}, 
     {'action': 'qux', 'people': ['d', 'e']}
    ]
  }, 
 {'event': 'bar', 
   'actions': [{'action': 'baz', 'people': ['b', 'a', 'c']}]
  }
 ]

It is not a less verbose answer, but maybe a bit better readable.这不是一个不那么冗长的答案,但也许可读性更好。 Also it does not depend on anything else and is just standard python.它也不依赖于其他任何东西,只是标准的 python。

tmp_dict = {}
for d in history:
    for event in d["events"]:
        if event not in tmp_dict:
            tmp_dict[event] = {}
            for actions in d["actions"]:
                tmp_dict[event][actions["action"]] = actions["people"]
        else:
            for actions in d["actions"]:
                if actions["action"] in tmp_dict[event]:
                    tmp_dict[event][actions["action"]].extend(actions["people"])
                else:
                    tmp_dict[event][actions["action"]] = actions["people"]

output = [{"event": event, "actions": [{"action": ac, "people": list(set(peop))} for ac, peop in tmp_dict[event].items()]} for event in tmp_dict]

print (output)

Output: Output:

[
   {'event': 'foo',
    'actions': [
                {'action': 'qux', 'people': ['e', 'd']},
                {'action': 'baz', 'people': ['a', 'c', 'b']}
               ]
   },
   {'event': 'bar',
    'actions': [{'action': 'baz', 'people': ['a', 'c', 'b']}]
   }
]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM