Как объединить два списка словарей в Python?

У меня есть следующие простые структуры данных:

teams = [ { 'league_id': 1, 'name': 'Kings' }, { 'league_id': 1, 'name': 'Sharkls' }, { 'league_id': 2, 'name': 'Reign' }, { 'league_id': 2, 'name': 'Heat' } ]
leagues = [ { 'league_id': 1, 'name': 'League 1' }, { 'league_id': 2, 'name': 'League 2' } ]

И у меня есть следующее dict понимание:

league_teams = { x['league_id']: [ t['name']
    for t in teams if t['league_id'] == x ['league_id'] ]
    for x in leagues }

Который дает:

{1: ['Kings', 'Sharkls'], 2: ['Reign', 'Heat']}

Есть ли более простой способ использования itertools или что-то, чтобы получить этот диктат? Это кажется немного громоздким.

3 ответа

Вот адаптация решения O(n+m) от Moinuddin Quadri, которое охватывает случай "пустой лиги" и которое, кстати, не требует импорта каких-либо модулей. Дикт output выполняет двойную обязанность как его league_ids установить, и так как он предварительно инициализирован, он не должен быть collections.defaultdict:

output = { league['league_id']:[] for league in leagues }
for team in teams:
    if team['league_id'] in output:
        output[team['league_id']].append(team['name'])
print(output)

Выход:

{1: ['Kings', 'Sharkls'], 2: ['Reign', 'Heat']}

Вы не должны itertools здесь вместо collections.defaultdict это лучший выбор. Сложность вашего решения O(n*m), тогда как с defaultdict, это будет O(n+m).

Вы можете достичь того, что вы хотите, как:

from collections import defaultdict

# create set to store `league_id` in `leagues`. Set holds unique
# values and also searching in set is faster than in normal list
leagues_id = set([item['league_id'] for item in leagues])

my_dict = defaultdict(list)

for item in teams:
    if item['league_id'] in leagues_id:
        my_dict[item['league_id']].append(item['name'])

где в конце my_dict будет держать значение:

{1: ['Kings', 'Sharkls'], 2: ['Reign', 'Heat']}

Изменить: Если вы также хотите, чтобы запись в my_dict для league_id Присутствует в лигах, но не в командах, вам нужно явно делать записи, такие как:

for leagues_id in leagues_ids:
     _ = my_dict[leagues_id]   # Will create empty list for such ids

Проверка t['league_id'] == x['league_id'] выглядит не обязательно.

Вы можете упростить с:

import collections

league_teams = collections.defaultdict(list)
for t in teams:
    league_teams[t['league_id']].append(t['name'])

Если вы действительно хотите itertools для этого:

import itertools

league_teams = {k: [t['name'] for t in g]
                for k, g in itertools.groupby(teams, key=lambda t: t['league_id'])}

Но это будет работать только в том случае, если список команд отсортирован.

Другие вопросы по тегам