2015-01-28 3 views
3

Я знаю, как простой инвертировать ключ и значение в словаре, когда значение уникально. Но как инвертировать, когда значение НЕ уникально. Согласно требованию, если значение отображается более одного раза, мне нужно использовать set, чтобы сделать их вместе.инвертировать ключ и значение в словаре в python3 (значение не уникально)


Ex. вход d = {'a':1, 'b':2,'c':1,'d':2} выход d = {1,{'a','c'},2,{'b','c'}}


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

def change(d): 

    inverted_l = list(map(lambda t:(t[1],t[0]), d.items())) 
    store_key = [] #for store the key to check if value appear more than one 
    new_d = {} 
    x = set() 
    for i in range(len(inverted_l)): 
     store_key.append(inverted_l[i][0]) 
    for i in range(len(store_key)): 
     if store_key.count(store_key[i])> 1: 
      x.add(inverted_l[i][1]) #I think the problem is I need create set 
            #each time, but I don't know how to do that 
      new_d[store_key[i]] = x 
     else: 
      new_d[store_key[i]] = inverted_l[i][1] 
    return new_d 

print(sorted(change({'a':1, 'b':2, 'c':1,'d':2}).items())) 

мой неправильный выход [(1, {'c', 'd', 'b', 'a'}), (2, {'c', 'd', 'b', 'a'})] Но мне нужно [(1, {'a', 'c'}), (2, {'b', 'd'})]

Добавлено: Стараюсь код, но ошибка происходит, когда я испытываю print(sorted(invert_dict({'a':1, 'b':2, 'c':1}).items())) Я хочу, чтобы мой результат [(1, {'a', 'c'}), (2, 'b')] Я новичок в Python, спасибо за вашу помощь и время!

def invert_dict(d): 
    result = {} 
    for k in d: 
     if d[k] not in result: 
      result[d[k]] = set() 
     result[d[k]].add(k) 
    return {k: d[k] if len(d[k])>1 else d[k].pop() for k in d} 



Traceback (most recent call last): 
    File "U:\test.py", line 9, in <module> 
    print(sorted(invert_dict({'a':1, 'b':2, 'c':1}).items())) 
    File "U:\test.py", line 7, in invert_dict 
    return {k: d[k] if len(d[k])>1 else d[k].pop() for k in d} 
    File "U:\test.py", line 7, in <dictcomp> 
    return {k: d[k] if len(d[k])>1 else d[k].pop() for k in d} 
TypeError: object of type 'int' has no len() 

ответ

5

Я уверен, что вы имеете в виду желаемый результат не набор

d = {1,{'a','c'},2,{'b','c'}} 

а словарь

d = {1:{'a','c'}, 2:{'b','c'}} 

Просто дважды проверить здесь :-).

Во всяком случае, я хотел бы сделать это:

import collections 

def invert_dict(d): 
    result = collections.defaultdict(set) 
    for k in d: 
     result[d[k]].add(k) 
    return dict(result) 

return может быть упрощена return result если dictподклассdefaultdict ОК - необходимо только, чтобы превратить его в dict, если спецификация очень строгий об этом.

Я полагаю, следующий шаг, вероятно, будет «ой, импорт не разрешается» запретить collections.defaultdict, поэтому я ожидаю, что - в этом случае, вместо того, чтобы сделать (например)

def invert_dict(d): 
    result = {} 
    for k in d: 
     if d[k] not in result: 
      result[d[k]] = set() 
     result[d[k]].add(k) 
    return result 

Добавлено: видимо, последняя версия имеет решающее значение (OP, конечно, «забыл», чтобы добавить ограничение «без импорта» в первую очередь - почему они держат , делая это мне ?! стоило бы им что-нибудь, чтобы выявить все ограничения спереди с самого начала в их Qs?!?!? !!), но нужна настройка - одиночные наборы должны быть превращены в не-множества их единственного элемента (ужасная, ужасная, нехорошая спецификация, что делает словарь почти непригодным для использования, и заставляя меня сильно хотеть иметь несколько острых слов с не-goodnicks, которые, кажется, верят что создание отвратительно плохих спекуляций улучшает их учение, но это еще одно написание).

Во всяком случае, лучше всего добавить шаг постобработки:

def invert_dict(d): 
    result = {} 
    for k in d: 
     if d[k] not in result: 
      result[d[k]] = set() 
     result[d[k]].add(k) 
    return {k: d[k] if len(d[k])>1 else d[k].pop() for k in d} 

Ничто не сложно: просто «раскручивание» синглтон устанавливает вниз к их один пункт с pop. (Что дальше - запоздалое откровение еще другой глупо произвольны ограничения, такие, как «нет, если/иначе выражений» -?!)

Добавлено (оставив глючный код выше): необходимо использовать result не d в return заявление ясно! I. Конечная строка должна быть

return {k: result[k] if len(result[k])>1 else result[k].pop() for k in result} 
+0

Ответ правильный! Но не могли бы вы сделать еще одно изменение? Я только хочу, чтобы ключ добавлял набор, когда он появился более одного раза. Ex. Ввод: d = {'a': 1, 'b': 2, 'c': 1} Выход должен быть d = {(1, {'a', 'c'}), (2, 'b')} , и ваш результат равен (1, {'a', 'c'}), (2, {'b'}). Спасибо! И ... импорт не разрешен для реального! как предвидение! – vivian

+0

Вы не можете заранее знать, будет ли снова повторяться 'd [k]', поэтому, чтобы избежать ужаса проверки типов, вам понадобится шаг последующей обработки - редактирование A, чтобы показать это. –

+0

Ну, возникает ошибка: TypeError: объект типа 'int' не имеет len(). Не могли бы вы исправить это ... – vivian