Объединить список диктантов

#python

Вопрос:

Итак, дан список словарей в следующем формате:

 [
  {
    'prod_instance': 'AEIS_PWH_SP1', 
    'testing_instance': 'AEIS_PWH_DA1', 
    'project_adm': 'scisae', 
    'vdb': 'aPWH - cpi', 
    'db_name': 'cpi'
  }, 
  {    
    'prod_instance': 'AEIS_PWH_SP1', 
    'testing_instance': 'AEIS_PWH_DA1', 
    'project_adm': 'scisae', 
    'vdb': 'aPWH - aeis', 
    'db_name': 'asis'
  }
]
 

Я хотел бы объединить словари, если prod_instance , testing_instance , и project_adm равны.

т. е. ожидаемый результат приведенного выше примера

 [
  {
    'prod_instance': 'AEIS_PWH_SP1', 
    'testing_instance': 'AEIS_PWH_DA1', 
    'project_adm': 'scisae', 
    'data_sources': [
      {
        'vdb': 'aPWH - cpi', 
        'db_name': 'cpi'
      },
      {
        'vdb': 'aPWH - aeis', 
        'db_name': 'asis'
      }
    ]    
  }
]
 

Конечно, я могу сделать это с помощью двойного for цикла, но (1) это O(n 2) и (2) это долго и некрасиво.

Может ли кто-нибудь придумать более элегантный способ?

Комментарии:

1. Можете ли вы предоставить свой код

2. Это имеет значение? Как упоминалось в конце моего вопроса, я знаю, что двойной цикл for работает, но мне это не нравится. Оптимальный ответ, если таковой имеется, в любом случае будет работать совсем иначе, чем мой нынешний подход. Это похоже на то, как если бы я просил алгоритм быстрой сортировки, когда я использую сортировку по пузырькам. Так какой смысл публиковать то, что у меня есть прямо сейчас?

Ответ №1:

Это то, чего ты хочешь?

 data = [
    {
        'prod_instance': 'AEIS_PWH_SP1',
        'testing_instance': 'AEIS_PWH_DA1',
        'project_adm': 'scisae',
        'vdb': 'aPWH - cpi',
        'db_name': 'cpi'
    },
    {
        'prod_instance': 'AEIS_PWH_SP1',
        'testing_instance': 'AEIS_PWH_DA1',
        'project_adm': 'scisae',
        'vdb': 'aPWH - aeis',
        'db_name': 'asis'
    }
]
res = {}
for i in data:
    # by @blhsing: tuple is easier and more efficient than string concatenation
    key = (i['prod_instance'], i['testing_instance'], i['project_adm'],)
    val = {
        'prod_instance': i['prod_instance'],
        'testing_instance': i['testing_instance'],
        'project_adm': i['project_adm'],
        'data_sources': []
    }
    data_sources = {
        'vdb': i['vdb'],
        'db_name': i['db_name']
    }
    res.setdefault(key, val)
    res[key]['data_sources'].append(data_sources)

result_list = list(res.values())
print(result_list)
 

Комментарии:

1. Да, это отлично работает. И это O(n). Как получилось, что я пропустил ту часть, в которой я могу объединить разные ключи в один. Это может быть немного чересчур, но есть ли какая-то стенография(ы), которую я могу использовать, чтобы минимизировать этот фрагмент кода? Извините, я не слишком хорошо знаком с Python.

2. Объединение ключей подвержено столкновениям. Он сломается, если у записи есть ключи, компоненты которых в имени перекрываются с компонентами другой записи. Например, если запись имеет prod_instance A_B значение «и testing_instance C «, она может столкнуться с записью, которая имеет prod_instance A значение «и testing_instance B_C «. Вряд ли это произойдет, но может произойти. Вместо этого лучше создать кортеж из составных ключей.

3. @blhsing Да, цель состоит в том, чтобы использовать уникальный ключ. Существует множество методов, и сращивание символов-самый простой из них.

4. Вы правы в этом, но, к счастью, я могу гарантировать, что в данном случае ключи имеют очень строгий формат. Поэтому в данном конкретном случае столкновения должны быть невозможны.

5. @blhsing Согласен, возражений нет.