Hiya, I'm developing a game as a hobby, and I am currently coding in a clothing shop. Every piece of clothing has a description, cost, and stat requirements. To organise this data, I've used nested dictionaries within a few class attributes.
Now I want the shopkeeper to have specific comment for some clothing brought, so I'd want to return/print the description every time a player buys a piece of clothing? How would I do that exactly?
My pseudo code/problem strategy has been to write a function, initiate a loop over the keys of the outer dictionary, then using a conditional to find the piece of clothing just brought, and looping through it's inner dictionary to find it's dictionary key, and printing out it's value, which is a string. Hope that helps you understand my thinking.
python - How to iterate through a nested dict? - Stack Overflow
python - Loop through all nested dictionary values? - Stack Overflow
python - Creating a nested dictionaries via for-loop - Stack Overflow
How to iterate over nested dictionaries in a LIST, using for loop
Videos
The following will work with multiple levels of nested-dictionary:
Copydef get_all_keys(d):
for key, value in d.items():
yield key
if isinstance(value, dict):
yield from get_all_keys(value)
d = {'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'dict3': {'baz': 3, 'quux': 4}}}
for x in get_all_keys(d):
print(x)
This will give you:
Copydict1
foo
bar
dict2
dict3
baz
quux
keys() method returns a view object that displays a list of all the keys in the dictionary
Iterate nested dictionary:
Copyd = {'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'baz': 3, 'quux': 4}}
for i in d.keys():
print i
for j in d[i].keys():
print j
OR
Copyfor i in d:
print i
for j in d[i]:
print j
output:
Copydict1
foo
bar
dict2
baz
quux
where i iterate main dictionary key and j iterate the nested dictionary key.
As said by Niklas, you need recursion, i.e. you want to define a function to print your dict, and if the value is a dict, you want to call your print function using this new dict.
Something like :
def myprint(d):
for k, v in d.items():
if isinstance(v, dict):
myprint(v)
else:
print("{0} : {1}".format(k, v))
There are potential problems if you write your own recursive implementation or the iterative equivalent with stack. See this example:
dic = {}
dic["key1"] = {}
dic["key1"]["key1.1"] = "value1"
dic["key2"] = {}
dic["key2"]["key2.1"] = "value2"
dic["key2"]["key2.2"] = dic["key1"]
dic["key2"]["key2.3"] = dic
In the normal sense, nested dictionary will be a n-nary tree like data structure. But the definition doesn't exclude the possibility of a cross edge or even a back edge (thus no longer a tree). For instance, here key2.2 holds to the dictionary from key1, key2.3 points to the entire dictionary(back edge/cycle). When there is a back edge(cycle), the stack/recursion will run infinitely.
root<-------back edge
/ \ |
_key1 __key2__ |
/ / \ \ |
|->key1.1 key2.1 key2.2 key2.3
| / | |
| value1 value2 |
| |
cross edge----------|
If you print this dictionary with this implementation from Scharron
def myprint(d):
for k, v in d.items():
if isinstance(v, dict):
myprint(v)
else:
print "{0} : {1}".format(k, v)
You would see this error:
> RuntimeError: maximum recursion depth exceeded while calling a Python object
The same goes with the implementation from senderle.
Similarly, you get an infinite loop with this implementation from Fred Foo:
def myprint(d):
stack = list(d.items())
while stack:
k, v = stack.pop()
if isinstance(v, dict):
stack.extend(v.items())
else:
print("%s: %s" % (k, v))
However, Python actually detects cycles in nested dictionary:
print dic
{'key2': {'key2.1': 'value2', 'key2.3': {...},
'key2.2': {'key1.1': 'value1'}}, 'key1': {'key1.1': 'value1'}}
"{...}" is where a cycle is detected.
As requested by Moondra this is a way to avoid cycles (DFS):
def myprint(d):
stack = list(d.items())
visited = set()
while stack:
k, v = stack.pop()
if isinstance(v, dict):
if k not in visited:
stack.extend(v.items())
else:
print("%s: %s" % (k, v))
visited.add(k)
You can simply achieve the expected behavior using collections.defaultdict and a simple loop.
NB. I am emulating a file with a split text here
f = '''GPU;GeForce GTX 1070 Ti;430
CPU;AMD Ryzen 7 2700X;233
GPU;GeForce GTX 2060;400
CPU;Intel Core i7-11700;360
RAM;HyperX 16GB;180
PSU;Corsair RM850X;210'''
from collections import defaultdict
out = defaultdict(dict)
for line in f.split('\n'):
typ,name,price = line.split(';')
out[typ][name] = price
dict(out)
output:
>>> dict(out)
{'GPU': {'GeForce GTX 1070 Ti': '430', 'GeForce GTX 2060': '400'},
'CPU': {'AMD Ryzen 7 2700X': '233', 'Intel Core i7-11700': '360'},
'RAM': {'HyperX 16GB': '180'},
'PSU': {'Corsair RM850X': '210'}}
with a file:
with open('file.txt') as f:
for line in f:
# rest of the loop from above
It's this part. You're replacing the value of your dictionary key.
outer_dict[type] = inner_dict
Instead change it to add a new sub-key like this
type = parts[0]
name = parts[1]
price = int(parts[2])
outer_dict[type][name] = price # add `name` to the `type` dict as a new key
Hey there,
I have an dictionary (essentially json) and I'm trying to iterate over it. I cant share the dictionary but essentially i dont know how many times it will be nested. If it isn't nested there is data i need to return. Issue is depending on one of the values, it might have another dictionary i need to loop over. I'm having trouble conceptualizing how to even write this.
The stupid in me pictures it as a for loop for each nest (just assume ill never see a nesting of more than 10) and write the outputs i need to another list. I think the better way to handle this is recursion but I'm not super confident with it.
Is there any other way i can access all items of each nest without knowing how many nests?
Sorry if this is very arbitrary. I'm having difficulty myself even trying to explain it.
Cheers