получить ключ-значение по значению из списка

Придумал себе задачку, чтобы практиковаться с листами и словарями и запутался напрочь.

Есть словарь из людей и инструментов.

{'Ivan ': ['guit', 'bass'], 'Stas': ['guit', 'bass', 'vox', 'keys'], 'Nick': ['drums', 'keys'], 'Sasha': ['vox', 'keys', 'guit']}

Нужно создать новый словарь где есть только три человека с тремя не повторяющимися инструментами. Желаю получить что-то вроде

{'Ivan ': ['guit'], 'Stas': ['bass'], 'Nick': ['drums']

Например, я делаю список существующих инструментов

['guit', 'bass', 'vox', 'synth', 'drums']

Рандом выбирает из списка инструмент и вот тут я не понимаю как по этому значению найти человека (любого) с этим инструментом и добавить в новый словарь


Ответы (2 шт):

Автор решения: Nimaniel

Ну, если я вас правильно понял, делается это так:

import random

instruments = ['guit', 'bass', 'vox', 'synth', 'drums']
musicians = {
    'Ivan ': ['guit', 'bass'], 
    'Stas': ['guit', 'bass', 'vox', 'synth'], 
    'Nick': ['drums', 'synth'], 
    'Sasha': ['vox', 'synth', 'guit']
    }

triple = random.sample(instruments, 3)
result = {}

for el in triple:
    for k, v in musicians.items():
        if el in v and k not in result:
            result[k] = el
            break

print(result)

Функция random.sample() выбирает из переданного списка три случайных неповторяющихся значения.

Далее простая проверка. Для каждого интересующего нас инструмента проверяем, кто из людей им владеет и нет ли такого человека у нас в результирующем списке.

Однако, как правильно заметил @GrAnd, этот алгоритм может выдавать в результате неполную тройку музыкантов, даже если такая существует.

Я вижу два решения этой проблемы. Во-первых, можно отсортировать словарь musicians по возрастанию ключей, хотя это может не помочь.

Во-вторых, можно находить все возможные комбинации подходящих музыкантов и выбирать самую длинную.

→ Ссылка
Автор решения: GrAnd

У меня получилось такое решение. Я использовал рекурсию чтобы в случае необходимости точно перебрать все варианты и найти комбинацию (или не найти) когда для всех инструментов найдутся музыканты.

import random

def solver(persons, inst_lst):
    for i, inst in enumerate(inst_lst):
        # список оставшихся инструментов
        other_inst_lst = inst_lst[:i] + inst_lst[i+1:]
        # итерируемся по людям у кого есть этот инструмент
        for name in dict(filter(lambda el: inst in el[1], persons.items())):
            # исключаем этого человека из дальнейшего поиска
            other_persons = dict(filter(lambda el: name != el[0], persons.items()))
            if other_inst_lst:
                if other_persons:
                    # ищем пару человек-инструмент в оставшихся людях и инструментах
                    res = solver(other_persons, other_inst_lst)
                    # если нашли, то добавляем к результату текущую пару человек-инструмент
                    if res: return [(name, inst)] + res
            else:
                # это был последний инструмент - возвращаем текущую пару
                return [(name, inst)]
    return None
 
PERSONS = {'Ivan' : ['guit' , 'bass'], 
           'Stas' : ['guit' , 'bass', 'vox', 'keys'], 
           'Nick' : ['drums', 'keys'], 
           'Sasha': ['vox'  , 'keys', 'guit']}

instruments = set(item for sublist in PERSONS.values() for item in sublist)
inst_choise = random.sample(instruments, 3)

print("Инструменты:", inst_choise)
print("Группа:", solver(PERSONS, inst_choise))
→ Ссылка