Extract values by key from a nested dictionary - python

Given this nested dictionary, how could I print all the "phone" values using a for loop?
people = {
'Alice': {
'phone': '2341',
'addr': '87 Eastlake Court'
},
'Beth': {
'phone': '9102',
'addr': '563 Hartford Drive'
},
'Randy': {
'phone': '4563',
'addr': '93 SW 43rd'
}

for d in people.values():
print d['phone']

Loop over the values and then use get() method, if you want to handle the missing keys, or a simple indexing to access the nested values. Also, for the sake of optimization you can do the whole process in a list comprehension :
>>> [val.get('phone') for val in people.values()]
['4563', '9102', '2341']

Using a list comprehension
>>> [people[i]['phone'] for i in people]
['9102', '2341', '4563']
Or if you'd like to use a for loop.
l = []
for person in people:
l.append(people[person]['phone'])
>>> l
['9102', '2341', '4563']

Related

In a Pythonic way I like a list to become key values as list items in an existing dict

I've got a list and a dict. Now I want the items in the list to be key values in the dict and they have to be new lists. In a pythonic way :-)
I got it working. But I guess not in a real pythonic way.
my_people = ['theo', 'Jan', 'Jason']
my_classes = {'class_1': {}, 'class_2': {}, 'class_3': {}}
my_classes['class_1'] = dict.fromkeys(my_people, 1)
for p in my_classes['class_1']:
my_classes['class_1'][p] = []
So is there a way to make the items lists without the last for p in my_classes loop?
Output: {'class_1': {'theo': [], 'Jan': [], 'Jason': []}, 'class_2': {}, 'class_3': {}}
If your input is as you show you can just use a dict comprehension:
my_people = ['theo', 'Jan', 'Jason']
my_classes = {'class_1': {}, 'class_2': {}, 'class_3': {}}
my_classes['class_1'] = {name: [] for name in my_people}
First of all, your variable my_classes isn't a dictionary. It's a set, a collection without duplicated itens.
For create the dictionary that you want you can use dict comprehension like that:
my_people = ['theo', 'Jan', 'Jason']
dictionary = { elem: [] for elem in my_people }
// -> {'theo': [], 'Jan': [], 'Jason': []}

How to get total number of repeated objects and respective keys from a python dictionary having multiple objects?

I have a python dictionary which consists of many nested dictionaries. I.e. it looks like this:
result = {
123: {
'route1': 'abc'
'route2': 'abc1'
},
456: {
'route1': 'abc'
'route2': 'abc1'
},
789: {
'route1': 'abc2'
'route2': 'abc3'
},
101: {
'route1': 'abc'
'route2': 'abc1'
},
102: {
'route1': 'ab4'
'route2': 'abc5'
}
}
Here we can see that 123, 456 and 101 has the same values.
What I am trying to do that is to find out the repeated object which in this case is:
{
'route1': 'abc'
'route2': 'abc1'
}
and the keys which have this repeated object i.e. 123, 456 and 101.
How can we do this?
Along with repeated objects info, I also want to know which objects does not repeat. I.e. 789 and its respective object and 102 and its respective object.
PS: Please note that I don't really know beforehand which objects are repeating as this structure will be generated inside code. So, it's possible that there could not be any repeated object or there could be multiple i.e. more than one.
Also, I can not use pandas or numpy etc. due to some restrictions.
You can do this by creating a dictionary holding all the matching keys for each distinct value in your result dict (where the values are themselves dicts). This is a fairly common pattern in Python, iterating through one container and aggregating values into a dict. Then, once you've created the aggregation dict, you can split it into duplicate and single values.
To build the aggregation dict, you need to use each subdict from result as a key and append the matching keys from the original dict to a list associated with that subdict. The challenge is that you can't use the subdicts directly as dictionary keys, because they are not hashable. But you can solve that by converting them to tuples. The tuples should also be sorted, to avoid missing duplicates that happen to pop out with different ordering.
It may be easier to understand just by looking at some example code:
result = {
123: {'route1': 'abc', 'route2': 'abc1'},
456: {'route1': 'abc', 'route2': 'abc1'},
789: {'route1': 'abc2', 'route2': 'abc3'},
101: {'route1': 'abc', 'route2': 'abc1'},
102: {'route1': 'ab4', 'route2': 'abc5'}
}
# make a dict showing all the keys that match each subdict
cross_refs = dict()
for key, subdict in result.items():
# make hashable version of subdict (can't use dict as lookup key)
subdict_tuple = tuple(sorted(subdict.items()))
# create an empty list of keys that match this val
# (if needed), or retrieve existing list
matching_keys = cross_refs.setdefault(subdict_tuple, [])
# add this item to the list
matching_keys.append(key)
# make lists of duplicates and non-duplicates
dups = {}
singles = {}
for subdict_tuple, keys in cross_refs.items():
# convert hashed value back to a dict
subdict = dict(subdict_tuple)
if len(keys) > 1:
# convert the list of matching keys to a tuple and use as the key
dups[tuple(keys)] = subdict
else:
# there's only one matching key, so use that as the key
singles[keys[0]] = subdict
print(dups)
# {
# (456, 123, 101): {'route2': 'abc1', 'route1': 'abc'}
# }
print(singles)
# {
# 789: {'route2': 'abc3', 'route1': 'abc2'},
# 102: {'route2': 'abc5', 'route1': 'ab4'}
# }
Use collections.defaultdict:
from collections import defaultdict
d = defaultdict(list)
for k, v in result.items():
d[tuple(v.items())].append(k)
desired = {
'route1': 'abc',
'route2': 'abc1'
}
d[tuple(desired.items())]
Output:
[456, 123, 101]
For not-repeated items, use list comprehension:
[v for v in d.values() if len(v) == 1]
Output:
[[102], [789]]
You can use drop_duplicates() function of pandas:
Firstly transforme your dict on dataframe
import pandas as pd `
df = pd.DataFrame(result).T
Output :
route1 route2
123 abc abc1
456 abc abc1
789 abc2 abc3
101 abc abc1
102 ab4 abc5
Then use the function drop_duplicates and transform to a dict
df2 = df1.drop_duplicates(subset=['route1', 'route2']).T.to_dict()
Output :
{
123: {
'route1': 'abc',
'route2': 'abc1'
},
789: {
'route1': 'abc2',
'route2': 'abc3'
},
102: {
'route1': 'ab4',
'route2': 'abc5'
}
}

Python Dict Comprehension to Create and Update Dictionary

I have a list of dictionaries (data) and want to convert it into dictionary (x) as below.
I am using following ‘for loop’ to achieve.
data = [{'Dept': '0123', 'Name': 'Tom'},
{'Dept': '0123', 'Name': 'Cheryl'},
{'Dept': '0123', 'Name': 'Raj'},
{'Dept': '0999', 'Name': 'Tina'}]
x = {}
for i in data:
if i['Dept'] in x:
x[i['Dept']].append(i['Name'])
else:
x[i['Dept']] = [i['Name']]
Output:
x -> {'0999': ['Tina'], '0123': ['Tom', 'Cheryl', 'Raj']}
Is it possible to implement the above logic in dict comprehension or any other more pythonic way?
The dict comprehension, even though not impossible, might not be the best choice. May I suggest using a defaultdict:
from collections import defaultdict
dic = defaultdict(list)
for i in data:
dic[i['Dept']].append(i['Name'])
It seems way too complicated to be allowed into any code that matters even the least bit, but just for fun, here you go:
{
dept: [item['Name'] for item in data if item['Dept'] == dept]
for dept in {item['Dept'] for item in data}
}

Dictionaries store pairs. Who stores triples?

We would use a dictionary to store for example:
a={"breakfast":"banana","lunch":"fish","dinner":"soup"}
What would your approach be if you want to add the time attribute alongside every key-value set. Of course not:
a={"8AM":"breakfast":"banana","2PM":"lunch":"fish","8PM":"dinner":"soup"}
Then I would like to use one or more keys to access a value.
Maybe by doing a trick with lists?
You can use a tuple as a dictionary key:
a = {("8AM", "breakfast"): "banana",
("2PM", "lunch"): "fish",
("8PM", "dinner"): "soup",
}
Use a dictionary with a tuple as the key:
>>> a={("8AM","breakfast"):"banana",("2PM","lunch"):"fish",("8PM","dinner"):"soup"}
>>> a["8AM","breakfast"]
'banana'
Or if you want to look up the time and the food using just the meal name:
>>> a={"breakfast":("8AM","banana"),"lunch":("2PM","fish"),"dinner":("8PM","soup")}
>>> a["breakfast"]
('8AM', 'banana')
Since you want to use a dictionary and possibly lists, I would recommend determining what your "primary key" is and creating a nested structure like this:
a = {
'breakfast': {
'time': "8AM",
'items': ['banana', 'yogurt']
},
'lunch': {
'time': '2PM',
'items': ['fish', 'tartar sauce']
},
'dinner': {
'time': '8PM',
'items': ['soup', 'salad']
}
}
The time for each meal is variable, but we all know we eat breakfast, lunch, and dinner (or at least we should). Doing this you can then determine the time and items that were consumed:
a['breakfast']['time']
'8AM'
a['breakfast']['items']
['banana', 'yogurt']
a = {"8AM":{"breakfast":"banana"},"2PM":{"lunch":"fish"},"8PM":{"dinner":"soup"}}
Using:
>>>a['8AM']['breakfast']
'banana'
Other:
def r(_d,_target):
result = []
for k, v in _d.items():
if(k == _target):
if type(v) == type({}):
for x in v.keys():
result.append(v[x])
else:
result.append(v)
if type(v) == type({}):
r2 = r(v,_target)
if len(r2) > 0:
for l in r2:
result.append(l)
return result
>>> r(a,"breakfast")
['banana']
>>> r(a,"8AM")
['banana']
>>> r(a,"dinner")
['soup']

What is the Pythonic way to iterate over a dict of dicts and lists?

I have a dict which contains some lists and some dicts, as illustrated below.
What is the most pythonic way to iterate over the dict and print out the name and address pairs for each top level dict key?
Thanks
{
'Resent-Bcc': [],
'Delivered-To': [],
'From': {'Name': 'Steve Watson', 'Address': 'steve.watson#example.org'},
'Cc': [],
'Resent-Cc': [],
'Bcc': [ {'Name': 'Daryl Hurstbridge', 'Address': 'daryl.hurstbridge#example.org'},
{'Name': 'Sally Hervorth', 'Address': 'sally.hervorth#example.org'},
{'Name': 'Mike Merry', 'Address': 'mike.merry#example.org'},
{'Name': 'Jenny Callisto', 'Address': 'jenny.callisto#example.org'}
],
'To': {'Name': 'Darius Jedburgh', 'Address': 'darius.jedburgh#example.org'}
}
Use the iteritems() method on the dict. It's clear and easy to understand: that seems Pythonic to me. iteritems() also creates less temporary items than items(), as Preet Kukreti mentioned in the comments. First, fix your data. Right now, some of the values in the top-level dict are lists, and some are more dicts:
# list
'Delivered-To': [],
# dict
'From': {'Name': 'Steve Watson', 'Address': 'steve.watson#example.org'},
This means you have to check the type of the value and act accordingly (and you might forget to check!). Make your data consistent:
# list
'Delivered-To': [],
# also list
'From': [{'Name': 'Steve Watson', 'Address': 'steve.watson#example.org'}],
This will prevent weird type-related bugs in the future. Since Python is an interpreted language, it's very easy to make type bugs and not notice until your code is in production and crashes. Try to make your code as type-safe as possible!
Then you can use something like this:
for k, v in d.iteritems():
for row in v:
if "Name" in row and "Address" in row:
print row["Name"], ":", row["Address"]
One way is to change the lone dicts into a list containing the dict. Then all the entries can be treated the same
>>> D = {
... 'Resent-Bcc': [],
... 'Delivered-To': [],
... 'From': {'Name': 'Steve Watson', 'Address': 'steve.watson#example.org'},
... 'Cc': [],
... 'Resent-Cc': [],
... 'Bcc': [ {'Name': 'Daryl Hurstbridge', 'Address': 'daryl.hurstbridge#example.org'},
... {'Name': 'Sally Hervorth', 'Address': 'sally.hervorth#example.org'},
... {'Name': 'Mike Merry', 'Address': 'mike.merry#example.org'},
... {'Name': 'Jenny Callisto', 'Address': 'jenny.callisto#example.org'}
... ],
... 'To': {'Name': 'Darius Jedburgh', 'Address': 'darius.jedburgh#example.org'}
... }
>>> L = [v if type(v) is list else [v] for v in D.values()]
>>> [(d["Name"], d["Address"]) for item in L for d in item ]
[('Steve Watson', 'steve.watson#example.org'), ('Daryl Hurstbridge', 'daryl.hurstbridge#example.org'), ('Sally Hervorth', 'sally.hervorth#example.org'), ('Mike Merry', 'mike.merry#example.org'), ('Jenny Callisto', 'jenny.callisto#example.org'), ('Darius Jedburgh', 'darius.jedburgh#example.org')]
Or the one liner version
[(d["Name"], d["Address"]) for item in (v if type(v) is list else [v] for v in D.values())]
It's probably best to keep your data simple, by making the naked dict's be a list of one element holding the original dict. Otherwise, you're kind of asking for harder to test code.
I tend to lean away from isinstance(foo, dict) and instead use things like:
if getattr(d, 'iteritems'): print list(d.iteritems())
...It strikes me as more duck-typed this way; it opens the door to using one of the many dict-replacements - things that act like a dict, but nominally aren't a dict.
for key in header:
if header[key] and type(header[key])==type([]):
for item in header[key]:
print (item)
elif type(header[key])==type({}):
print(header[key])
# this option is not the easiest to read, so I classify it as less "pythonic"
l = [header[key] for key in header if header[key] and type(header[key])==type({})] + [header[key][i] for key in header if header[key] and type(header[key])==type([]) for i in range(len(header[key]))]
for item in l:
print(item)
if you're looking for the contents of a specific header you could modify the if statements accordingly. Both of these examples print the dictionaries, but could easily be adapted to print specific values.
for i in dict:
if 'Name' in dict[i]:
print (dict[i]['Name'],dict[i]['Address'])
this will not work for the bcc where its in a list (right now it will only print the from and to names and addresses) Do you need it to print the bcc addresses too?

Categories