Reputation: 767
Code:
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)
Problem: For the last for
loop (sorting one) to show all entries of dictionary names
, I need all the entries i.e. duplicate keys (one-to-many mapping) also. But 2 Tom(s)
and 1 Bernie
are missed out while creating nested dictionary users
. How can it be avoided using python 3.4?
Upvotes: 2
Views: 3571
Reputation: 123531
Dictionaries cannot have duplicate keys, so the original data would need to be changed into something else...such as a list of full-name strings that contained both the first and last name separated by spaces.
Before Python 3.6, the items in dictionaries are unorderd, so you could instead store the results in a collections.OrderedDict
subclass to preserve the order that the keys were inserted if you wished to have it retained (which will continue work in Python 3.6 as well as earlier versions).
Putting everthing together, would result in something like this:
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)
Output:
OrderedDict([('Amanda', ['Roberts']),
('Bernie', ['Zunks', 'Barbie']),
('Bucky', ['Roberts']),
('Dean', ['Hayes']),
('Jenna', ['Hayes']),
('Tom', ['Roberts', 'Williams', 'Jones'])])
Upvotes: 2
Reputation: 8730
@Rex5, dictionary is defined as an unordered collection of items with unique keys.
Keys should be immutable data items but values can be mutable/immutable both.
So, definition itself is filtering out the duplicated values while creating names dictionary hence there is no chance of having the duplicated copies inside for loops.
Have a look at the below sample example. I have also modified your code example after this.
Focus on keys Sam and Kim.
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"
# }
I have also tried to provide an alternative answer that fulfills the need as follows (What I did is I just modified the dictionary and for loop).
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'}
"""
Upvotes: 1
Reputation: 22324
A dict
cannot have duplicate keys, you might want to consider another data structure such as a list of tuples.
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]
Upvotes: 3
Reputation: 1649
You could also use a defaultdict
Consider the below
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
Outputs:
defaultdict(list,
{'Amanda': ['Roberts'],
'Bernie': ['Zunks', 'Barbie'],
'Bucky': ['Roberts'],
'Dean': ['Hayes'],
'Jenna': ['Hayes'],
'Sally': ['Jones'],
'Tom': ['Roberts', 'Williams', 'Jones']})
Explanation
names = defaultdict(list)
initializes a dictionary that creates an empty list instead of throwing a KeyError
when a key that doesn't exist is queried.
Therefore you can just append to new keys as though they were in the dict.
Making the users list can be as below
users = []
for fname in names:
for lname in names[fname]:
users.append({'fname': fname, 'lname': lname})
Upvotes: 1
Reputation: 5825
A few possible improvements, but to your main issue, use the full name and a set
as your structure, and split
on space to create the other dict (which I am not sure you need):
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)
Produces:
{'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'}
EDIT: using tuples and adding 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)
With output:
{'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'}
Upvotes: 4