2016-10-31 2 views
0

Мне нужно преобразовать приведенный выше список кортежей вложенным словаря без перезаписи значения, как показано ниже в питонаСписок кортежей вложенным словаря без перекрывая

[('a', '1'), 
    ('b', 'true'), 
    ('b', 'none'), 
    ('a', '2'), 
    ('b', 'true'), 
    ('a', '3'), 
    ('b', 'false')] 


{'a': {'1' : { 'b' : ('true','none')}, 
     '2' : { 'b' : ('true')}, 
     '3' : { 'b' : ('false')}}} 

Преобразование каждого кортежа в словарь, используя

dict() 

и слияние словаря не работает. Есть ли какой-нибудь питонический способ сделать это?

+0

Ваша проблема неясна. Вы уверены, что каждый кортеж будет «a» или «b», за которым следует целое число в строковой форме или элемент данных для размещения в кортеже? Являются ли целые числа (в строковом формате) гарантированными последовательными? [Должен сказать, я не вижу смысла в такой структуре словаря, только с одним «а» и с повторяющимися «b'''s» - ни одна из которых не добавляет никакой информации.] –

+0

Я предложу вы перебираете свой список и разлагаете его на 'key' и' value' из его кортежа, а затем проверяете, существует ли 'key' в вашем' словаре', получая его предыдущее значение «tuple», преобразовывая его в «list», добавляя new 'value', а затем снова сделать его« tuple »и установить его как новый словарь« key ». Если это неясно, дайте мне знать, и я дам ** реальный код python ** * ASAP * ':)' –

+0

@RoryDaulton Да, каждый кортеж будет 'a' или 'b', за которым следуют некоторые данные, которые будут строка. Целые числа, показанные здесь, например. Это не должно быть последовательным. – Alex

ответ

1

Вот один из способов сделать это с collections.defaultdict:

from collections import defaultdict 
import pprint 

data = [('a', '1'), ('b', 'true'), ('b', 'none'), ('a', '2'), ('b', 'true'), ('a', '3'), ('b', 'false')] 

d = defaultdict(lambda: defaultdict(lambda: defaultdict(tuple)))  
for i, j in data: 
    if i == 'a': 
     p = d[i][j] 
    else: 
     p[i] += j, 

pprint.pprint(d) 
# {'a': {'1': defaultdict(<class 'tuple'>, {'b': ('true', 'none')}), 
#  '2': defaultdict(<class 'tuple'>, {'b': ('true',)}), 
#  '3': defaultdict(<class 'tuple'>, {'b': ('false',)})}} 

Вы также можете использовать setdefault метод Словаре, чтобы вернуть значения по умолчанию для новых ключей, хотя defaultdict подход намного чище и быстрее:

c = {} 
for i, j in data: 
    if i == 'a': 
     q = c.setdefault(i, {}).setdefault(j, {}) 
    else: 
     q[i] = q.setdefault(i,()) + (j,) 

pprint.pprint(c) 
# {'a': {'1': {'b': ('true', 'none')}, 
#  '2': {'b': ('true',)}, 
#  '3': {'b': ('false',)}}} 
+0

Может использовать 'for i, j в данных' вместо' for i в data', чтобы он выглядел немного аккуратно :) –

+0

@ Farhan.K Да, это , Looks neater :) –

+0

Если во внешнем dict есть только 'a', вы можете сначала генерировать внутренний dict, а затем обернуть это в dict с помощью ключа' a'. – xZise

0

Расширение @MosesKoledoye ответ, если первое значение в словаре составляет только 'a' и 'b', вы знаете, что внешний словарь будет всегда содержат не более одного элемента, используя 'a', поскольку ключ и внутренний словарь всегда будут содержать не более одного элемента, используя 'b' в качестве ключа. Поэтому в конце вы получите ту же информацию, если она равна {'1': ('true', 'none')…. Вы можете преобразовать это в свой формат, просто обернув данные в некоторые словари. Это означает, что вы можете сделать следующее

output = defaultdict(tuple) 
for i, j in data: 
    if i == 'a': 
     current = j 
    else: 
     # i == 'b' 
     output[current] += (j,) 

Это приведет к следующему:

defaultdict(<type 'tuple'>, {'1': ('true', 'none'), '3': ('false',), '2': ('true',)}) 

Теперь, чтобы получить его в словарь, как ваша вы можете сделать следующее:

output = {k: {'b': v} for k, v in output.items()} 
if output: 
    output = {'a': output} 

В результате:

{'a': {'1': {'b': ('true', 'none')}, '3': {'b': ('false',)}, '2': {'b': ('true',)}}}