如何在值相同的情况下合并具有相同键的dicts列表?

时间:2017-08-21 10:17:34

标签: python dictionary merge

Python newbe在这里。我看过Stack Overflow但是找不到与此完全相似的问题。我试图合并一个具有相同键和值相同的dicts列表(所以在我的情况下合并名称是相同的)。

这是我目前的清单:

final = [
  {
    'name': 'food festival',
    'category': ['Miscellaneous', 'Undefined'],
    'shows': [
      {
        'start': '2017-10-04T14:30:00Z',
        'venue': 'venue_1',
        'prices': [
          { 'price_1' : 100 },
          { 'price_2' : 120}
        ]
      },
      {
        'start': '2017-11-04T14:30:00Z',
        'venue': 'venue_2',
        'prices': [
          { 'price_1': 150 },
          { 'price_2' : 200 }
        ]
      }
    ]
  },
  {
    'name': 'music festival',
    'category': ['music', 'pop'],
    'shows': [
      {
        'start': '2017-12-04T14:30:00Z',
        'venue': 'venue_3',
        'prices': [
          { 'price_1' : 300 },
          { 'price_2' : 320}
        ]
      }
   ]
  }
]

这就是我想要实现的目标:

headers.append('Authorization', 'Bearer ${this.auth.token}');

2 个答案:

答案 0 :(得分:1)

以下是一些代码:

from pprint import pprint as pp


current = [
    {'name' : 'food festival', 'category' : ['Miscellaneous', 'Undefined'], 'venue' : 'venue_1', 'price_1' : 100, 'price_2' : 120, 'start' : '2017-10-04T14:30:00Z'},
    {'name' : 'food festival', 'category' : ['Miscellaneous', 'Undefined'], 'venue' : 'venue_2', 'price_1' : 150, 'price_2' : 200, 'start' : '2017-11-04T14:30:00Z'},
    {'name' : 'music festival', 'category': ['music', 'pop'], 'venue' : 'venue_3', 'price_1' : 300, 'price_2' : 320, 'start' : '2017-12-04T14:30:00Z'}
]


SPECIAL_EVENT_KEYS = ("name", "category")
INVALID_INDEX = -1


def convert_event(event, special_event_keys=SPECIAL_EVENT_KEYS):
    ret = dict()
    prices_list = list()
    for key in event:
        if key in special_event_keys:
            continue
        elif key.startswith("price_"):
            prices_list.append({key: event[key]})
        else:
            ret[key] = event[key]
    ret["prices"] = prices_list
    return ret


def merge_events_data(events, special_event_keys=SPECIAL_EVENT_KEYS):
    ret = list()
    for event in events:
        existing_index = INVALID_INDEX
        for idx, obj in enumerate(ret):
            for key in special_event_keys:
                if obj[key] != event[key]:
                    break
            else:
                existing_index = idx
        if existing_index == INVALID_INDEX:
            new_object = dict()
            for key in special_event_keys:
                new_object[key] = event[key]
            new_object["shows"] = [convert_event(event, special_event_keys=special_event_keys)]
            ret.append(new_object)
        else:
            ret[existing_index]["shows"].append(convert_event(event, special_event_keys=special_event_keys))
    return ret;


def main():
    merged_events = merge_events_data(current)
    print("\nResulting object:\n")
    pp(merged_events)
    #print("Equal:", merged_events == final) # Commented out to avoid including the contents of 'final' in the answer as it would get too large; add it and decomment for testing purpose


if __name__ == "__main__":
    main()

备注

  • 该算法依赖于以下事实:如果2个(输入)事件具有相同的键值:namecategory,它们将合并在一起(通过shows列表),否则它们将是合并结果中的单独条目
  • convert_event:在初始列表中获取事件,并将其转换为输出列表的事件
    • 删除namecategory
    • 将字典中的prices_*条目聚合为与prices键对应的列表
  • merge_events_data:迭代初始事件列表和
    • 如果输出列表中没有事件(没有匹配namecategory值的条目),则会创建
    • 如果找到此类事件,其内容(shows)会使用当前事件数据进行扩充
  • 代码是 Python3 Python2 兼容
  • 绝对可以从样式和性能 PoV
  • 进行改进

输出:

e:\Work\Dev\StackOverflow\q45794604>c:\Install\x64\Python\3.5.3\python.exe a.py

Merged object:

[{'category': ['Miscellaneous', 'Undefined'],
  'name': 'food festival',
  'shows': [{'prices': [{'price_2': 120}, {'price_1': 100}],
             'start': '2017-10-04T14:30:00Z',
             'venue': 'venue_1'},
            {'prices': [{'price_2': 200}, {'price_1': 150}],
             'start': '2017-11-04T14:30:00Z',
             'venue': 'venue_2'}]},
 {'category': ['music', 'pop'],
  'name': 'music festival',
  'shows': [{'prices': [{'price_2': 320}, {'price_1': 300}],
             'start': '2017-12-04T14:30:00Z',
             'venue': 'venue_3'}]}]

答案 1 :(得分:0)

您的数据结构有点令人困惑。我假设输入current必须按原样修复,但我已将final更改为更清晰。我认为这种格式的final将更有用,更清晰,但如果你真的想要final的其他版本,请告诉我。

import pprint

current = [
    {'name' : 'food festival', 'category' : ['Miscellaneous', 'Undefined'], 'venue' : 'venue_1', 'price_1' : 100, 'price_2' : 120, 'start' : '2017-10-04T14:30:00Z'},
    {'name' : 'food festival', 'category' : ['Miscellaneous', 'Undefined'], 'venue' : 'venue_2', 'price_1' : 150, 'price_2' : 200, 'start' : '2017-11-04T14:30:00Z'},
    {'name' : 'music festival', 'category': ['music', 'pop'], 'venue' : 'venue_3', 'price_1' : 300, 'price_2' : 320, 'start' : '2017-12-04T14:30:00Z'}
    ]

final = {}

for fest in current:
    name = fest["name"]
    if name not in final:
        final[name] = {"category": fest["category"],
                       "shows": []}

    show = {attr: fest[attr] for attr in ["start", "venue", "price_1", "price_2"]}

    final[name]["shows"].append(show)

pprint.pprint(final)

这有输出:

{'food festival': {'category': ['Miscellaneous', 'Undefined'],
                   'shows': [{'price_1': 100,
                              'price_2': 120,
                              'start': '2017-10-04T14:30:00Z',
                              'venue': 'venue_1'},
                             {'price_1': 150,
                              'price_2': 200,
                              'start': '2017-11-04T14:30:00Z',
                              'venue': 'venue_2'}]},
 'music festival': {'category': ['music', 'pop'],
                    'shows': [{'price_1': 300,
                               'price_2': 320,
                               'start': '2017-12-04T14:30:00Z',
                               'venue': 'venue_3'}]}}

注意:我使用的字典理解可能特定于某些版本的Python3,我不确定。它可以很容易地替换为

    show = dict((attr, fest[attr]) for attr in ["start", "venue", "price_1", "price_2"])

我没有太大改变 - 主要是最终版本是dict,其中节日的名称是代表它的字典的关键,我只是保持{{1} }和price_1作为键,因为它们只有两个,在我看来并不能证明词典列表是正确的。

另一个建议:您可以使用Python的price_2对象而不是字符串"Undefined"