Pythonic way to hash through dict of dicts dynamically? [duplicate] - python

This question already has answers here:
Automatically add key to Python dict
(3 answers)
Closed 7 years ago.
Suppose I create a dict like so:
foods = {}
And I eventually want to mutate some value of a nested dict within foods that doesn't yet exist:
foods['fruit']['apples'] = ['Granny Smith']
Is there a nice way to accomplish this insertion without checking the whole way:
if 'fruit' not in foods:
foods['fruit'] = {}
if 'apples' not in foods['fruit']:
foods['fruit']['apples'] = []
foods['fruit']['apples'].append('Granny Smith')
I guess I'm looking for a way to dynamically hash into nested dicts without explicitly instantiating them along the way.

I love the Python standard library. You want to use collections.defaultdict.
In this case, you want to nest them, so that foods is a defaultdict that, on the requested item not existing, generates a defaultdict that, on the requested item not existing, generates a list. Sounds complicated, but in the end, the result is not:
>>> from collections import defaultdict
>>> foods = defaultdict(lambda: defaultdict(list))
>>> foods['fruit']['apples'].append('Granny Smith')
>>> print(foods['fruit']['apples'])
['Granny Smith']

Your code:
if 'fruit' not in foods:
foods['fruit'] = {}
if 'apples' not in foods['fruit']:
foods['fruit']['apples'] = []
foods['fruit']['apples'].append('Granny Smith')
would be written as:
foods.setdefault('fruit', {}).setdefault('apples', []).append('Granny Smith')
Using setdefault(key[, default]).

Related

how do you append a list to a dictionary value in Python?

So if you have some dictionary like this
dictionary={}
dictionary['a']=1
dictionary['a']=2
print(dictionary)
this would print {'a':2} and replaces the 1
Is there any way I can add 2 to the key 'a' as a list ?
I know i can do something this like:
dictionary['a']=[1,2]
but I don't want to do it like this.
Essentially what i am asking is how can i add the new value to my key using a list instead of replacing the previous value.
Appreciate the help!
dictionary = {}
dictionary['a'] = []
dictionary['a'].append(1)
dictionary['a'].append(2)
print(dictionary)
It would be worth considering using a defaultdict if every value in the dict is/will be a list:
from collections import defaultdict
d = defaultdict(list)
d['a'].append(1)
d['a'].append(2)

Create many empty dictionary in Python

I'm trying to create many dictionaries in a for loop in Python 2.7. I have a list as follows:
sections = ['main', 'errdict', 'excdict']
I want to access these variables, and create new dictionaries with the variable names. I could only access the list sections and store an empty dictionary in the list but not in the respective variables.
for i in enumerate(sections):
sections[i] = dict()
The point of this question is. I'm going to obtain the list sections from a .ini file, and that variable will vary. And I can create an array of dictionaries, but that doesn't work well will the further function requirements. Hence, my doubt.
Robin Spiess answered your question beautifully.
I just want to add the one-liner way:
section_dict = {sec : {} for sec in sections}
For maintaining the order of insertion, you'll need an OrderedDict:
from collections import OrderedDict
section_dict = OrderedDict((sec, {}) for sec in sections)
To clear dictionaries
If the variables in your list are already dictionaries use:
for var in sections:
var.clear()
Note that here var = {} does not work, see Difference between dict.clear() and assigning {} in Python.
To create new dictionaries
As long as you only have a handful of dicts, the best way is probably the easiest one:
main = {} #same meaning as main = dict() but slightly faster
errdict = {}
excdict = {}
sections = [main,errdict,excdict]
The variables need to be declared first before you can put them in a list.
For more dicts I support #dslack's answer in the comments (all credit to him):
sections = [dict() for _ in range(numberOfDictsYouWant)]
If you want to be able to access the dictionaries by name, the easiest way is to make a dictionary of dictionaries:
sectionsdict = {}
for var in sections:
sectionsdict[var] = {}
You might also be interested in: Using a string variable as a variable name

Breaking down list of list into dictionaries

I have a list of list, s, that is the result of querying a database on Fruit, item[0] is the name of the fruit, item[1] is the whether or not the fruit has seeds, and item[2] is whether or not it's edible.
s = [['Apple','Yes','Edible'], ['Watermellon','Yes','Yes']]
As my actual list is much bigger, I would like a really easy way to reference/return these values. For example, print my_dict['Apple']['Seeds'] would yield Yes
I think my best option would be to create a dictionary, but am looking for recommendations on if this is a good method and how to do this.
I started writing some code but am not sure how to get the second set of headers in place, so my example uses an index instead.
my_dict = {t[0]:t[1:] for t in s}
print my_dict['Apple'][0]
fruit_map = {
fruit: {'Seeds': seeds, 'Edible': edible} for fruit, seeds, edible in s}
If the second set of keys never changes, it would be better to define a proper object with fields. This might seem overkill or to verbose, but there is always collections.namedtuple to help.
namedtuple creates a new class from a list of field names. That class also supports being initialized by a list. To use your example:
import collections
Fruit = collections.namedtuple('Fruit', ['name', 'seeds', 'edible'])
This way, you can easily create Fruit objects from a list:
f = Fruit('Apple', True, False)
# Or, if you already have a list with the values
params = ['Apple', True, False]
f = Fruit(*params)
print f.seed
So you can create a list of fruits in a very easy way:
s = [['Apple','Yes','Edible'], ['Watermellon','Yes','Yes']]
fruits = [Fruit(*l) for l in s]
You really need to have a dictionary indexed by a certain field, it is not much different:
s = [['Apple','Yes','Edible'], ['Watermellon','Yes','Yes']]
fruit_dict = {l[0]: Fruit(*l) for l in s}
print(fruit_dict['Apple'].seeds)
namedtuples can be very convenient when transforming lists of values into more easy to use objects (such as when reading a CSV file, which is a case very similar to what you are asking).
import copy
def list_to_dict(lst):
local = copy.copy(lst) # copied lst to local
fruit = [i.pop(0) for i in local] # get fruit names
result = {}
for i in range(len(local)):
result[fruit[i]] = local[i]
return result
This returns the dictionary you want.

How can I get Python to automatically create missing key/value pairs in a dictionary? [duplicate]

This question already has answers here:
Is there a standard class for an infinitely nested defaultdict?
(6 answers)
Closed 9 years ago.
I'm creating a dictionary structure that is several levels deep. I'm trying to do something like the following:
dict = {}
dict['a']['b'] = True
At the moment the above fails because key 'a' does not exist. At the moment I have to check at every level of nesting and manually insert an empty dictionary. Is there some type of syntactic sugar to be able to do something like the above can produce:
{'a': {'b': True}}
Without having to create an empty dictionary at each level of nesting?
As others have said, use defaultdict. This is the idiom I prefer for arbitrarily-deep nesting of dictionaries:
def nested_dict():
return collections.defaultdict(nested_dict)
d = nested_dict()
d[1][2][3] = 'Hello, dictionary!'
print(d[1][2][3]) # Prints Hello, dictionary!
This also makes checking whether an element exists a little nicer, too, since you may no longer need to use get:
if not d[2][3][4][5]:
print('That element is empty!')
This has been edited to use a def rather than a lambda for pep8 compliance. The original lambda form looked like this below, which has the drawback of being called <lambda> everywhere instead of getting a proper function name.
>>> nested_dict = lambda: collections.defaultdict(nested_dict)
>>> d = nested_dict()
>>> d[1][2][3]
defaultdict(<function <lambda> at 0x037E7540>, {})
Use defaultdict.
Python: defaultdict of defaultdict?
Or you can do this, since dict() function can handle **kwargs:
http://docs.python.org/2/library/functions.html#func-dict
print dict(a=dict(b=True))
# {'a': {'b' : True}}
If the depth of your data structure is fixed (that is, you know in advance that you need mydict[a][b][c] but not mydict[a][b][c][d]), you can build a nested defaultdict structure using lambda expressions to create the inner structures:
two_level = defaultdict(dict)
three_level = defaultdict(lambda: defaultdict(dict))
four_level = defaultdict(lamda: defaultdict(lambda: defaultdict(dict)))

Python procedure to populate dictionary from data in 2 separate lists

I am trying to create an automated python procedure that uses two separate lists to create a dictionary and so far I am failing. I have two sorted lists where the nth item in the fist list corresponds to the nth item in the second list and I want to combine them into a dictionary.
For example, a subset of the 2 lists are as follows;
name = ['Adam', 'Alfred', 'Amy', 'Andy', 'Bob']
year = [1972, 1968, 1985, 1991, 1989]
I would want my output to be:
birth_years = {'Adam':1972, 'Alfred':1968, 'Amy':1985, 'Andy':1991, 'Bob':1989}
I was trying to do this with a for loop, but I could not get it to work. I appreciate any help.
Use the zip and dict functions to construct a dictionary out of a list of tuples:
birth_years = dict(zip(name, year))
And if you're curious, this would be how I would try to do it with a for loop:
birth_years = {}
for index, n in enumerate(name):
birth_years[n] = years[index]
I think I like the first example more.
birth_years = {}
for i in range(len(name)):
birth_years[name[i]] = year[i]
Try a dictionary comprehension:
birth_years = {nm:year[idx] for idx, nm in enumerate(name)}
Your lists would be better named names and years. You got off to a good start by trying to do it with a for loop. Most practical data processing problems involve error checking, which is just a tad difficult with one-liners. Example:
birth_years = {}
for i, name in enumerate(names):
if name in birth_years:
log_duplicate(i, name, years[i]))
else:
birth_years[name] = years[i]

Categories