I'm trying to create a dictionary that takes a key and returns another dictionary that takes a different key and returns a value, but I'm having difficulty on implementing this.
I've tried something like this:
FirstDict[key1]=SecondDict
SecondDict[key2]=Final Value
I'd like to be able to call it like SecondDict[key1][key2] but I'm unable to do so.
You can create multi-level nested dictionaries with collections.defaultdict, like this
from collections import defaultdict
def multi_level_dict():
return defaultdict(multi_level_dict)
You can use it like this
my_dict = multi_level_dict()
my_dict[1][2][3] = "cabbage"
my_dict[1][4][5] = "salad"
from pprint import pprint
pprint(my_dict)
# {1: {2: {3: 'cabbage'},
# 4: {5: 'salad'}}}
>>> a = {}
>>> b = {}
>>> a['key1'] = b
>>> b['key2'] = 'final value'
>>> a['key1']
{'key2': 'final value'}
>>> a['key1']['key2']
'final value'
>>>
I tested, it works!
You can create nested dictionaries with NestedDict
>>> from ndicts.ndicts import NestedDict
>>> nd = NestedDict()
>>> nd["a", "a"] = 0
>>> nd["a", "b"] = 1
>>> nd["b"] = 2
>>> nd
NestedDict({'a': {'a': 0, 'b': 1}, 'b': 2})
Once you have a NestedDict, get value using tuples as in a flat dictionary
>>> nd["a", "a"]
0
To install ndicts pip install ndicts
Related
So I have a dict, which contains keys corresponding to a list, which contains str. I want to collect all the same values in said list and sum them together. Perhaps my explanation was confusing so I'll provide an example:
function_name({'key1':['apple', 'orange'], 'key2':['orange', 'pear'})
>>> {'apple':1, 'orange':2, 'pear':1}
How would I create this function? I was thinking of somehow making a for loop like this:
count = 0
for fruit in dict_name:
if food == 'apple'
count = count + fruit
I am still unsure about how to format this especially how to count the values and collect them, thanks in advance for any suggestions!
You can un-nest the dict's values and apply a Counter.
>>> from collections import Counter
>>>
>>> d = {'key1':['apple', 'orange'], 'key2':['orange', 'pear']}
>>> Counter(v for sub in d.values() for v in sub)
Counter({'apple': 1, 'orange': 2, 'pear': 1})
If you don't like the nested generator comprehension, the un-nesting can be done with itertools.chain.from_iterable.
>>> from itertools import chain
>>> Counter(chain.from_iterable(d.values()))
Counter({'apple': 1, 'orange': 2, 'pear': 1})
Without imports and with traditional loops, it would look like this:
>>> result = {}
>>> for sub in d.values():
...: for v in sub:
...: result[v] = result.get(v, 0) + 1
...:
>>> result
{'apple': 1, 'orange': 2, 'pear': 1}
Something like this should do the trick:
>>> from collections import Counter
>>> counts = Counter([item for sublist in your_dict.values() for item in sublist])
If you don't want to import any libraries you can do as follows:
function_name = {'key1':['apple', 'orange'], 'key2':['orange', 'pear']}
foobar = {}
for key, value in function_name.items():
for element in value:
if element in foobar:
foobar[element] += 1
else:
foobar[element] = 1
print(foobar)
You check if the value is already in the created dict 'foobar'. If it is you add its value by one. If its not, then you add the value as a key and define its value as one. :)
I tried using dict.fromkeys([1,2,3],set()). This initializes creates the dictionary but when I add a value to any one of the sets all the sets get updated!
>>> d=dict.fromkeys([1,2,3],set())
>>> d
>>> {1: set(), 2: set(), 3: set()}
>>> d[1].add('a')
>>> d
>>> {1: {'a'}, 2: {'a'}, 3: {'a'}}
It seems that all the three values of the dictionary are referring to the same set. I want to initialize all the values of the dictionary to empty sets so that I can perform some operations on these sets in a loop based on the keys later.
Using dictionary comprehension
d = {x: set() for x in [1, 2, 3]}
Or using collections.defaultdict
You can use collections.defaultdict
>>> from collections import defaultdict
>>> d = defaultdict(set)
>>> d[1].add('a')
>>> d
defaultdict(<class 'set'>, {1: {'a'}})
>>> d[2].add('b')
>>> d
defaultdict(<class 'set'>, {1: {'a'}, 2: {'b'}})
The way it works, is, when you try to add a value to a key like dict[key].add(value), it checks whether the key is present; if so, then it adds the value to the set. If it is not present the value is added as a set since the default is set as a set (defaultdict(set)).
You want a defaultdict so you don't need to initialize the sets in the first place:
>>> from collections import defaultdict
>>> d = defaultdict(set)
# That's it, initialization complete. Use goes like this:
>>> d[1].add('a')
>>> d[2].add('b')
>>> d[3].add('c')
>>> d
defaultdict(<class 'set'>, {1: {'a'}, 2: {'b'}, 3: {'c'}})
I have a dictionary which I need to deconstruct its keys and values in perhaps two lists(or any other type that does the job) and later in another function, construct the exact same dictionary putting back the keys and values. What's the right way of approaching this?
You can use dict.items() to get all the key-value pairs from the dictionary, then either store them directly...
>>> d = {"foo": 42, "bar": 23}
>>> items = list(d.items())
>>> dict(items)
{'bar': 23, 'foo': 42}
... or distribute them to two separate lists, using zip:
>>> keys, values = zip(*d.items())
>>> dict(zip(keys, values))
{'bar': 23, 'foo': 42}
d = {'jack': 4098, 'sape': 4139}
k, v = d.keys(), d.values()
# Do stuff with keys and values
# -
# Create new dict from keys and values
nd = dict(zip(k, v))
Better Don't deconstruct it. Where you need the keys and values as list you can get that with the following methods.
keyList=list(dict.keys())
valueList = [dict[key] for key in keyList] or [dict[key] for key in dict.keys()]
Hope it helps.
To deconstruct a Dict to two list
>>> test_dict={"a":1, "b":2}
>>> keyList=[]
>>> valueList =[]
>>> for key,val in test_dict.items():
... keyList.append(key)
... valueList.append(val)
>>> print valueList
[1, 2]
>>> print keyList
['a', 'b']
To construct from two list of key and value I would use zip method along with dict comprehension.
>>> {key:val for key,val in zip(keyList,valueList)}
{'a': 1, 'b': 2}
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})})})
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']}