несколько ключей во вложенном словаре - PullRequest
0 голосов
/ 19 мая 2018

Код :

from operator import itemgetter
names = {
    'Bucky': 'Roberts',
    'Tom': 'Roberts',
    'Bernie' : 'Zunks',
    'Jenna' : 'Hayes',
    'Sally': 'Jones',
    'Amanda':'Roberts',
    'Tom':'Williams',
    'Dean':'Hayes',
    'Bernie':'Barbie',
    'Tom':'Jones'
    }
users = []
for k,v in names.items():
    users.append({'fname':k,'lname':v})
print(users)
for x in sorted(users, key=itemgetter('fname')):
    print(x)

Проблема : для последнего цикла for (сортировка по одному), чтобы показать все записи словаря names, Iнужны все записи, т.е. дубликаты ключей (сопоставление один ко многим).Но 2 Tom(s) и 1 Bernie упускаются при создании вложенного словаря users.Как этого избежать, используя python 3.4?

Ответы [ 5 ]

0 голосов
/ 19 мая 2018

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

До Python 3.6 элементы в словарях неупорядочены, поэтому вы можете вместо этого сохранить результаты в подклассе collections.OrderedDict, чтобы сохранить порядок, в котором ключи были вставлены, если вы хотите сохранить его (который продолжит работу в Python 3.6 кактакже как и более ранние версии).

Если соединить все вместе, получится что-то вроде этого:

from collections import OrderedDict
from operator import itemgetter
from pprint import pprint

names = ['Bucky Roberts',
         'Tom Roberts',
         'Bernie Zunks',
         'Jenna Hayes',
         'Amanda Roberts',
         'Tom Williams',
         'Dean Hayes',
         'Bernie Barbie',
         'Tom Jones',]

users = OrderedDict()
for name in sorted(names):
    fname, lname = name.split()
    users.setdefault(fname, []).append(lname)

pprint(users)

Вывод:

OrderedDict([('Amanda', ['Roberts']),
             ('Bernie', ['Zunks', 'Barbie']),
             ('Bucky', ['Roberts']),
             ('Dean', ['Hayes']),
             ('Jenna', ['Hayes']),
             ('Tom', ['Roberts', 'Williams', 'Jones'])])
0 голосов
/ 19 мая 2018

@ Rex5 , словарь определяется как неупорядоченный набор элементов с уникальными ключами.

Ключи должны быть неизменяемыми элементами данных, но значения могут быть как изменяемыми, так и неизменяемыми.

Таким образом, само определение отфильтровывает дублирующиеся значения при создании словаря names , следовательно, нет шансов получить дублированные копии.внутри для петель.

Посмотрите на пример ниже.После этого я также изменил ваш пример кода.

Фокус на клавишах Сэм и Ким .

import json

# Creating list of users (Dictionary) with duplicated keys
users = {
"Sam": "Smith",
"Samuel": "Badri",
"Kim": "Jones",
"Jim": "Hollowen",
"Sam": "Paul",
"Joel": "Brown",
"Kim": "Fillo",
"Sam": "Koelli",
"Tinnu": "Timmon"
}

# Pretty printing the dictionary
# Keys, Sam & Kim will appear only once even after their multiple occurrences
print( json.dumps(users, indent=4))

# {
#    "Kim": "Fillo",
#    "Sam": "Koelli",
#    "Tinnu": "Timmon",
#    "Jim": "Hollowen",
#    "Joel": "Brown",
#    "Samuel": "Badri"
# }

Я также попытался дать альтернативный ответ, который удовлетворяет потребности следующим образом (я только что изменил словарь и цикл for).

from operator import itemgetter
names = {
    'Bucky': 'Roberts',
    'Tom': ['Roberts', 'Williams', 'Jones'],
    'Bernie' : ['Zunks', 'Barbie'],
    'Jenna' : 'Hayes',
    'Sally': 'Jones',
    'Amanda':'Roberts',
    'Dean':'Hayes',
}

users = []
for k,v in names.items():
    if type(v) == type([]):
        for lname in v:
            users.append({'fname': k, 'lname': lname})
    else:
        users.append({'fname':k, 'lname':v})

print(users)

"""
[{'lame': 'Zunks', 'fname': 'Bernie'}, {'lname': 'Barbie', 
'fname': 'Bernie'}, {'lname': 'Jones', 'fname': 'Sally'}, 
{'lname': 'Hayes', 'fname': 'Jenna'}, {'lname': 'Roberts', 
'fname': 'Amanda'}, {'lname': 'Roberts', 'fname': 'Bucky'}, 
{'lname': 'Hayes', 'fname': 'Dean'}, {'lname': 'Roberts', 
'fname': 'Tom'}, {'lname': 'Williams', 'fname': 'Tom'}, 
{'lname': 'Jones', 'fname': 'Tom'}]
"""

for x in sorted(users, key=itemgetter('fname')):
    print(x)

"""
{'lname': 'Roberts', 'fname': 'Amanda'}
{'lname': 'Zunks', 'fname': 'Bernie'}
{'lname': 'Barbie', 'fname': 'Bernie'}
{'lname': 'Roberts', 'fname': 'Bucky'}
{'lname': 'Hayes', 'fname': 'Dean'}
{'lname': 'Hayes', 'fname': 'Jenna'}
{'lname': 'Jones', 'fname': 'Sally'}
{'lname': 'Roberts', 'fname': 'Tom'}
{'lname': 'Williams', 'fname': 'Tom'}
{'lname': 'Jones', 'fname': 'Tom'}
"""
0 голосов
/ 19 мая 2018

Вы также можете использовать defaultdict

Рассмотрите следующие

from collections import defaultdict

names = defaultdict(list)

names['Bucky'].append('Roberts')

names['Tom'].append('Roberts')

names['Bernie'].append('Zunks')

names['Jenna'].append('Hayes')

names['Sally'].append('Jones')

names['Amanda'].append('Roberts')

names['Tom'].append('Williams')

names['Dean'].append('Hayes')

names['Bernie'].append('Barbie')

names['Tom'].append('Jones')
print names

Выходы:

defaultdict(list,
            {'Amanda': ['Roberts'],
             'Bernie': ['Zunks', 'Barbie'],
             'Bucky': ['Roberts'],
             'Dean': ['Hayes'],
             'Jenna': ['Hayes'],
             'Sally': ['Jones'],
             'Tom': ['Roberts', 'Williams', 'Jones']})

Пояснение

names = defaultdict(list) инициализирует словарь, который создает пустой список вместо броска KeyError, когда запрашивается ключ, который не существует.

Поэтому выможно просто добавить к новым ключам, как если бы они были в dict.

Составление списка пользователей может быть как ниже

users = []

for fname in names:
    for lname in names[fname]:
        users.append({'fname': fname, 'lname': lname})
0 голосов
/ 19 мая 2018

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

from operator import itemgetter

names = [
    ('Bucky', 'Roberts'),
    ('Tom', 'Roberts'),
    ('Bernie', 'Zunks'),
    ('Jenna', 'Hayes'),
    ('Sally', 'Jones'),
    ('Amanda','Roberts'),
    ('Tom', 'Williams'),
    ('Dean', 'Hayes'),
    ('Bernie', 'Barbie'),
    ('Tom', 'Jones')
    ]

users = [{'fname': k,'lname': v} for k, v in names]
0 голосов
/ 19 мая 2018

Несколько возможных улучшений, но к вашей основной проблеме, используйте полное имя и set в качестве вашей структуры, и split в пространстве для создания другого диктанта (который, я не уверен, вам нужен):

names = {
    'Bucky Roberts',
    'Tom Roberts',
    'Bernie Zunks',
    'Jenna Hayes',
    'Sally Jones',
    'Amanda Roberts',
    'Tom Williams',
    'Dean Hayes',
    'Bernie Barbie',
    'Tom Jones'
}

users = []
for name in names:
    k, v = name.split()
    users.append({'fname':k,'lname':v})
for x in sorted(users, key=itemgetter('fname')):
    print(x)

Производит:

{'fname': 'Amanda', 'lname': 'Roberts'}
{'fname': 'Bernie', 'lname': 'Barbie'}
{'fname': 'Bernie', 'lname': 'Zunks'}
{'fname': 'Bucky', 'lname': 'Roberts'}
{'fname': 'Dean', 'lname': 'Hayes'}
{'fname': 'Jenna', 'lname': 'Hayes'}
{'fname': 'Sally', 'lname': 'Jones'}
{'fname': 'Tom', 'lname': 'Williams'}
{'fname': 'Tom', 'lname': 'Jones'}
{'fname': 'Tom', 'lname': 'Roberts'}

РЕДАКТИРОВАТЬ: используя кортежи и добавляя Betty Sue Johnson:

names = {
    ('Bucky', 'Roberts'),
    ('Betty Sue', 'Johnson'),
    ('Tom', 'Roberts'),
    ('Bernie', 'Zunks'),
    ('Jenna', 'Hayes'),
    ('Sally', 'Jones'),
    ('Amanda', 'Roberts'),
    ('Tom', 'Williams'),
    ('Dean', 'Hayes'),
    ('Bernie', 'Barbie'),
    ('Tom', 'Jones')
}

for each in sorted([{'fname':n[0], 'lname':n[1]} for n in names], key=itemgetter('fname')):
    print(each)

С выводом:

{'fname': 'Amanda', 'lname': 'Roberts'}
{'fname': 'Bernie', 'lname': 'Zunks'}
{'fname': 'Bernie', 'lname': 'Barbie'}
{'fname': 'Betty Sue', 'lname': 'Johnson'}
{'fname': 'Bucky', 'lname': 'Roberts'}
{'fname': 'Dean', 'lname': 'Hayes'}
{'fname': 'Jenna', 'lname': 'Hayes'}
{'fname': 'Sally', 'lname': 'Jones'}
{'fname': 'Tom', 'lname': 'Roberts'}
{'fname': 'Tom', 'lname': 'Williams'}
{'fname': 'Tom', 'lname': 'Jones'}
...