Usage of setdefault instead of defaultdict - python

I need to create a structure like this :
D = {i:{j:{k:0,l:1,m:2}},a:{b:{c:0,d:4}}}
So this can be done using defaultdict:
D = defaultdict(defaultdict(Counter))
How do i use setdefault here?
EDIT :
Is it possible to combine setdefault and defaultdict ?

To build a multi-level dictionary with setdefault() you'd need to repeatedly access the keys like this:
>>> from collections import Counter
>>> d = {}
>>> d.setdefault("i", {}).setdefault("j", Counter())
Counter()
>>> d
{'i': {'j': Counter()}}
To generalize the usage for new keys you could use a function:
def get_counter(d, i, j):
return d.setdefault(i, {}).setdefault(j, Counter())

Related

Python [Nested Dictionary] - How to add new key/values to create this structure of dictionary: d = {key:{key:value, key:value, key:value}}

I hope you're good.
Can you help me to create this structure of dictionary and add the values in a loop?
d = {'key1':{'key(a)':'value', 'key(b)':'value', 'key(c)':'value'}, 'key2':{'key(a)':'value', 'key(b)':'value', 'key(c)':'value'}}
Below, a real example for you to understand my goal
d = {'ABCD3':{'2010':'25.0', '2011':'28.0', '2012':'24.0'}, RBRP11{'2010':'21.0', '2011':'30.0', '2012':'40.0'}}
This kind of structure will be easy to search after or do you have a better suggestion of structure?
defaultdict is what you need:
from collections import defaultdict
d = defaultdict(dict)
then you can do:
d['foo'][a] = 1
d['foo'].update({'b': 2, 'c': 3})
if you want to nest deeper:
d = defaultdict(lambda: defaultdict(dict))
d['foo']['bar'] = dict(a=1)
d['foo']['bar']['b'] = 2
d['foo']['bar'].update({'c': 3})

Nested dictionary with defaults

Is there a way to make a nested dictionary such that I can say mydict[x][y][z] += 1, where mydict[x][y][z] did not previously exist, and defaults to 0 (and would be 1 after incrementing)?
I looked into answers to a similar question in which you can say mydict[x][y][z] = 1 using defaultdict from the collections class (Declaring a multi dimensional dictionary in python), but this does not allow you to assume a default value and then increment.
Yes, you can do this with the collections module:
from collections import defaultdict, Counter
d = defaultdict(lambda: defaultdict(lambda: Counter()))
d['A']['B']['C'] += 1
# defaultdict(<function __main__.<lambda>>,
# {'A': defaultdict(<function __main__.<lambda>.<locals>.<lambda>>,
# {'B': Counter({'C': 1})})})
Note this is also possible via only using nested defaultdict:
d = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
However, given Counter was created for the specific purpose of incrementing integers, this would be the method I prefer.

Python: Concise way of updating a dictionary

Often when I'm working with dictionaries whose values are lists, I happen to code this:
if k in D:
D[k].append(x)
else:
D[k] = [x]
Is there a more concise way of doing this?
You can use a collections.defaultdict:
from collections import defaultdict
D = defaultdict(list)
D[k].append(x)
The most concise way is to use setdefault like:
D.setdefault(k, []).append(x)

recursive dictionary creation python

is there any way to dynamically create missing keys if i want to want to set a variable in a subdictionary.
essentially I want to create any missing keys and set my value.
self.portdict[switchname][str(neighbor['name'])]['local']['ports'] = []
currently i'm doing it but its messy:
if not switchname in self.portdict:
self.portdict[switchname] = {}
if not str(neighbor['name']) in self.portdict[switchname]:
self.portdict[switchname][str(neighbor['name'])] = {}
if not 'local' in self.portdict[switchname][str(neighbor['name'])]:
self.portdict[switchname][str(neighbor['name'])]['local'] = {}
if not 'ports' in self.portdict[switchname][str(neighbor['name'])]['local']:
self.portdict[switchname][str(neighbor['name'])]['local']['ports'] = []
Is there any way to do this in one or two lines instead?
This is easier to do without recursion:
def set_by_path(dct, path, value):
ipath = iter(path)
p_last = next(ipath)
try:
while True:
p_next = next(ipath)
dct = dct.setdefault(p_last, {})
p_last = p_next
except StopIteration:
dct[p_last] = value
And a test case:
d = {}
set_by_path(d, ['foo', 'bar', 'baz'], 'qux')
print d # {'foo': {'bar': {'baz': 'qux'}}}
If you want to have it so you don't need a function, you can use the following defaultdict factory which allows you to nest things arbitrarily deeply:
from collections import defaultdict
defaultdict_factory = lambda : defaultdict(defaultdict_factory)
d = defaultdict_factory()
d['foo']['bar']['baz'] = 'qux'
print d
Use collections.defaultdict
self.portdict = defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: []))))
I've run into a similar problem in the past. I found that defaultdict was the right answer for me—but writing the super long definitions (like the one in #o11c's answer or #Apero's answer) was no good. Here's what I came up with instead:
from collections import defaultdict
from functools import partial
def NestedDefaultDict(levels, baseFn):
def NDD(lvl):
return partial(defaultdict, NDD(lvl-1)) if lvl > 0 else baseFn
return defaultdict(NDD(levels-1))
This creates a dictionary with levels of nested dictionaries. So if you have levels=3, then you need 3 keys to access the bottom-level value. The second argument is a function which is used to create the bottom-level values. Something like list or lambda: 0 or even dict would work well.
Here's an example of using the "automatic" keys with 4 levels, and list as the default function:
>>> x = NestedDefaultDict(4, list)
>>> x[1][2][3][4].append('hello')
>>> x
defaultdict(<functools.partial object at 0x10b5c22b8>, {1: defaultdict(<functools.partial object at 0x10b5c2260>, {2: defaultdict(<functools.partial object at 0x10b5c2208>, {3: defaultdict(<type 'list'>, {4: ['hello']})})})})
I think that's basically what you'd want for the case in your question. Your 4 "levels" are switch-name, neighbor-name, local, & ports—and it looks like you want a list at the bottom-level to store your ports.
Another example using 2 levels and lambda: 0 as the default:
>>> y = NestedDefaultDict(2, lambda: 0)
>>> y['foo']['bar'] += 7
>>> y['foo']['baz'] += 10
>>> y['foo']['bar'] += 1
>>> y
defaultdict(<functools.partial object at 0x1021f1310>, {'foo': defaultdict(<function <lambda> at 0x1021f3938>, {'baz': 10, 'bar': 8})})
Have a close look to collections.defaultdict:
from collections import defaultdict
foo = defaultdict(dict)
foo['bar'] = defaultdict(dict)
foo['bar']['baz'] = defaultdict(dict)
foo['bar']['baz']['aaa'] = 1
foo['bor'] = 0
foo['bir'] = defaultdict(list)
foo['bir']['biz'].append(1)
foo['bir']['biz'].append(2)
print foo
defaultdict(<type 'dict'>, {'bir': defaultdict(<type 'list'>, {'biz': [1, 2]}), 'bor': 0, 'bar': defaultdict(<type 'dict'>, {'baz': defaultdict(<type 'dict'>, {'aaa': 1})})})

How to convert this list into dictionary in Python?

I have a list like this:
paths = [['test_data', 'new_directory', 'ok.txt'], ['test_data', 'reads_1.fq'], ['test_data', 'test_ref.fa']]
I want to convert this into dictionary like this:
{'test_data': ['ok.txt', 'reads_1.fq'], 'test_data/new_directory', ['ok.txt']}
The list is dynamic. The purpose of this is to create a simple tree structure. I want to do this using itertools like this:
from itertools import izip
i = iter(a)
b = dict(izip(i, i))
Is something like this possible? Thanks
can try this also,
list1=['a','b','c','d']
list2=[1,2,3,4]
we want to zip these two lists and create a dictionary dict_list
dict_list = zip(list1, list2)
dict(dict_list)
this will give:
dict_list = {'a':1, 'b':2, 'c':3, 'd':4 }
Yes it is possible, use collections.defaultdict:
>>> from collections import defaultdict
>>> dic = defaultdict(list)
>>> lis = [['test_data', 'new_directory', 'ok.txt'], ['test_data', 'reads_1.fq'],
for item in lis:
key = "/".join(item[:-1])
dic[key].append(item[-1])
...
>>> dic
defaultdict(<type 'list'>,
{'test_data': ['reads_1.fq', 'test_ref.fa'],
'test_data/new_directory': ['ok.txt']})
using simple dict:
>>> dic = {}
>>> for item in lis:
key = "/".join(item[:-1])
dic.setdefault(key, []).append(item[-1])
...
>>> dic
{'test_data': ['reads_1.fq', 'test_ref.fa'],
'test_data/new_directory': ['ok.txt']}

Categories