Инвертировать словарь со списками разной длины в Python 3.X - PullRequest
0 голосов
/ 18 ноября 2018

Это мой код (вдохновленный кодом в другом потоке):

def inverter(a):
    b = {}
    for k,v in a.items():
        for i in v:
            b.setdefault(i,[]).append(k)
    return b

x={'orange':['apple','peach'], 'cherry':'grape'}
print(inverter(x))

проблема в том, что он возвращает этот вывод:

{'apple': ['orange'], 'peach': ['orange'], 'g': ['cherry'], 'r': ['cherry'], 'a': ['cherry'], 'p': ['cherry'], 'e': ['cherry']}

Кажется, он повторяется по каждой буквепоследнего значения, вместо итерации один раз.Как мне это решить?Спасибо

Ответы [ 5 ]

0 голосов
/ 18 ноября 2018

Как уже писали другие, проблема в том, что иногда ваши значения являются списками, а иногда ваши значения являются строками, которые действуют как итеративные. Одно из возможных решений:

def inverter(a):
    b = []
    for k,v in a.items():
        if isinstance(v,list):
            b.extend([[x,k] for x in v])
        else: 
            b.append([v,k])
    return dict(b)

x={'orange':['apple','peach'], 'cherry':'grape'}
print(inverter(x))

Из:

{'apple': 'orange', 'peach': 'orange', 'grape': 'cherry'}
0 голосов
/ 18 ноября 2018

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

Вы можете использовать троичный оператор для условной логики.Также более эффективным будет использование collections.defaultdict:

from collections import defaultdict

def inverter(a):
    b = defaultdict(list)
    for k,v in a.items():
        for i in v if isinstance(v, list) else [v]:
            b[i].append(k)
    return b

x = {'orange':['apple','peach'], 'cherry':'grape'}

print(inverter(x))

defaultdict(<class 'list'>,
            {'apple': ['orange'], 'peach': ['orange'], 'grape': ['cherry']})
0 голосов
/ 18 ноября 2018

Комментарий MisterMiyagi является причиной вашей проблемы. Итерируя по v, где v='grape', вы получаете каждую отдельную букву, потому что вы перебираете строку. Чтобы это исправить, вы можете проверить тип экземпляра:

def inverter(a):

    b = {}
    for k,v in a.items():
        if isinstance(v, list):
            for i in v:
                b.setdefault(i,[]).append(k)
        else:
            b.setdefault(v, []).append(k)
    return b
x={'orange':['apple','peach'], 'cherry':'grape'}
print(inverter(x))
0 голосов
/ 18 ноября 2018

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

Обратите внимание на следующее:

def pairs_from_dict(d): 
    for k, v in d.items():
        if isinstance(v, str):
            yield (v, k)
        else:
            yield from ((k_i, k) for k_i in v)

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

Предполагается также, что все значения, из которых вы хотите создать ключи, являются уникальными, например, нет {'cherry': 'grape', 'banana':'grape'} в исходном словаре, потому что ключи словаря должны быть уникальными.

Работает так:

>>> d = {'orange':['apple','peach'], 'cherry':'grape'}
>>> dict(pairs_from_dict(d))
{'apple': 'orange', 'grape': 'cherry', 'peach': 'orange'}
0 голосов
/ 18 ноября 2018

Это решило проблему.Если есть более элегантные решения там, оценят:

def inverter(a):
b = {}
for k,v in a.items():
    if type(v) is list:
        for i in v:
            b.setdefault(i,[]).append(k)
    else:
        b.setdefault(v,[]).append(k)

return b

x={'orange':['apple','peach'], 'cherry':'grape'}
print(inverter(x))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...