Appending to Nested Dictionary with Identical Keys - python

I have a list containing values that should be used as keys for a dictionary. Right now the list to be converted to keys looks like the following:
myList = ["A", "B"]
I am converting this list to be the keys to a dictionary by doing the following:
newDict = dict.fromkeys(myList, {"Min":[], "Max":[], "Avg":[]})
When printing newDict I get the output:
{'A': {'Min': [], 'Max': [], 'Avg': []}, 'B': {'Min': [], 'Max': [], 'Avg': []}}
However, when trying to write to the newDict["B"]["Avg"] list, the value gets added to both the "A" and "B" keys:
Code:
newDict["B"]["Avg"].append(111)
Output:
{'A': {'Min': [], 'Max': [], 'Avg': [111]}, 'B': {'Min': [], 'Max': [], 'Avg': [111]}}
Is there for the appended value to only be added to the intended key?

This comes a lot when handling arrays and dicts.
What I prefer to do is use list/dict comprehensions to initialize a new object every time.
newDict = {k: {"Min":[], "Max":[], "Avg":[]} for k in myList}
With the initial method, your keys are pointing at the same object with the same id. You may briefly check this with a simple
newDict['A'] is newDict['B'] # True
class names can be camelCase, but not variables. Maybe pep8 will help you further in your journey through python. Thank you.

That's because both the keys are given the value {"Min":[], "Max":[], "Avg":[]}, which is the one dict in both case, rather than two identical dicts.
You can verify by calling id on each dict.
[id(v) for v in newDict.values()] # gives [4618156608, 4618156608]
Or as #FlorianAendekerk suggested, with is
newDict["A"] is newDict["B"] # gives True
You can fix it by creating a new dictionnary for each key for instance with a dict comprehenssion:
newDict = {k: {"Min":[], "Max":[], "Avg":[]} for k in myList}
PS. you should check out PEP8 as variables are not suposed to be camelCase or PascalCase.

Related

Checking if value is present in the list of key-value pairs, if not present then add the new key-pair value from iterables (not overwriting same key)

If I used the not in it still appends the new key-pair value even if a specific value is already in the list.
dict1 = {'a': 0, 'a': 5, 'b': 1, 'c': 2}
list1 = [{'a': 0}] # This key-pair value is already in the list1 but
# still added from dict1.
new1 = []
new2 = []
for key, value in dict1.items():
if value not in list1:
new1.append(key)
new2.append(value)
new0 = {new1[i]: new2[i] for i in range(len(new1))}
list1.append(new0)
Desired output is:
list1 = [{'a': 0, 'a': 5, 'b': 1, 'c': 2}]
(As I dont want to overwrite the key/s)
As you do not provide example data, I have to make some guesses here. If I guessed incorrectly, please provide the required information.
You call .items on list1. A list does not have a items function. Instead, I suspect your list1 is actually a dictionary, which would like this for example:
list1 = {
"a":1,
"b":2,
"c":3
}
In your current loop, you check if the value is within list2. If list2 is actually a list, you're doing so correctly. However, based on your title I assume what you actually want to do is check if the key is in list2, and if not add the key:value to list2. You could not add a key:value pair to a list, so I assume that list2 shoudl also be a dictionary. You would be able to add them add as a tuple, but based on the title I assume that is not what you want.
If you actually want to add it as a key:value pair to a dictionary, you could do that as follows:
list2 = {}
for key, value in list1.items():
if key not in list2.keys(): # check if this key already exists
list2[key] = value # if not, add they key with the value
As list1 and list2 are not actually instances of list, but of dict I would recommend renaming your variables to avoid future confusion. Hope that helps!
EDIT after update in question
Your example data had a small mistake, as there were two a keys, meaning that the first {'a':0} would be overwritten within dict1 already.
dict1 = {'a': 0, 'b': 5, 'c': 1, 'd': 2}
list1 = [{'a': 0}]
As I understand it, you wish to check if the value is already containted within a list of dictionaries.
As such, we need to get all the values from these dictionaries.
As you do not want to overwrite any keys, it would need to be a list of dictionaries that each only have one key. As such, we can get each individual dictionary, get the keys. This returns an dict_keys object, which we can convert to a list. Since each dictionary within list1 always only has one key, we can just take the first from said lsit.
[list(x.values())[0] for x in list1]
Putting that within the loop we get
for key, value in dict1.items():
if not value in [list(x.values())[0] for x in list1]:
# If no dictionary exists within `list1` with this value
list1.append({key:value}) # then add it as a new dictionary
This would return
[{'a': 0}, {'b': 5}, {'c': 1}, {'d': 2}]
You could run this code again with a different dict1 and it would not overwrite keys within list1, for example with:
dict1 = {'a': 9}
the output would become
[{'a': 0}, {'b': 5}, {'c': 1}, {'d': 2}, {'a': 9}]

update dictionary in nested loop

I am having trouble updating a dictionary. i am just extracting certain fields within each key - but the output is not as expected. data, expected output and code are below. Thanks for looking, i appreciate any comments
categories = {'categories_a1' : [{'group': '13GH9', 'number': '1'},{'group': '17KPO', 'number': '73'}, {'group': '26BN11', 'number': '2'}, {'group': '813W', 'number': '99'}],
'categories_a2' : [{'group': '99ITY', 'number': '12'},{'group': 'JH871', 'number': '15'}, {'group': 'OLH83', 'number': '99'}, {'group': '44RTQ', 'number': '1'}]}
xpected= {'categories_a1' : [{'13GH9': '1'},{'17KPO':'73'}, {'26BN11':'2'}, {'813W': '99'}],
'categories_a2' : [{'99ITY':'12'},{'JH871': '15'}, {'OLH83': '99'}, {'44RTQ':'1'}]}
out={}
for k in categories.keys():
for i in categories[k]:
x = {k: v for k, v in zip([i['group']], [i['number']])}
out[k] = x
out.update(out)
Let's first clean up some general weirdness:
out.update(out)
This line does effectively nothing and should be omitted.
x = {k: v for k, v in zip([i['group']], [i['number']])}
This makes little sense; we create lists with one element each and iterate over them in parallel. We could just as easily just use those values directly: x = {i['group']: i['number']}.
After swapping that in, let's consider the part that causes the actual problem:
for i in categories[k]:
x = {i['group']: i['number']}
out[k] = x
The problem here is that you want out[k] to constitute a list of all of the modified dictionaries, but x is repeatedly being assigned one of those dictionaries, and the result then becomes out[k]. What you presumably intended to do is repeatedly append those dictionaries to a new empty list:
x = []
for i in categories[k]:
x.append({i['group']: i['number']})
out[k] = x
However, it's clear that you're already familiar and comfortable with comprehensions, and this is an ideal place to use one:
out[k] = [{i['group']: i['number']} for i in categories[k]]
And, of course, we can extend this technique to the overall loop:
out = {
k: [{i['group']: i['number']} for i in v]
for k, v in categories.items()
}
Please carefully study the structure of this code and make sure you understand the technique. We have a source dictionary that we want to transform to create our output, and the rule is: the key remains unchanged, the value (which is a list) undergoes its own transformation. So we start by writing the skeleton for a dict comprehension, using .items() to give us key-value pairs:
out = {
k: # we need to fill in something to do with `v` here
for k, v in categories.items()
}
Then we figure out what we're doing with the value: each element of the list is a dictionary; the way that we process the list is iterative (each element of the input list tells us an element to use in the output list), but the processing of those elements is not (we look at exactly two hard-coded values from that dict, and make a dict from them). Given an element i of the list, the corresponding dict that we want has exactly one key-value pair, which we can compute as {i['group']: i['number']}. So we wrap a list comprehension around that: [{i['group']: i['number']} for i in v]; and we insert that into the dict comprehension skeleton, giving us the final result.
One approach:
for key, value in categories.items():
categories[key] = [{ d["group"] : d["number"] } for d in value]
print(categories)
Output
{'categories_a1': [{'13GH9': '1'}, {'17KPO': '73'}, {'26BN11': '2'}, {'813W': '99'}], 'categories_a2': [{'99ITY': '12'}, {'JH871': '15'}, {'OLH83': '99'}, {'44RTQ': '1'}]}

How to find and append dictionary values which are present in a list

I have a list which has unique sorted values
arr = ['Adam', 'Ben', 'Chris', 'Dean', 'Flower']
I have a dictionary which has values as such
dict = {
'abc': {'Dean': 1, 'Adam':0, 'Chris':1},
'def': {'Flower':0, 'Ben':1, 'Dean':0}
}
From looking at values from arr I need to have each item and if the value isn't present in subsequent smaller dict that should be assigned a value -1
Result
dict = {
'abc': {'Adam':0, 'Ben':-1, 'Chris':1, 'Dean': 1, 'Flower':-1},
'def': {'Adam':-1, 'Ben':1, 'Chris':-1, 'Dean': 0, 'Flower':0}
}
how can I achieve this using list and dict comprehensions in python
dd = {
key: {k: value.get(k, -1) for k in arr}
for key, value in dd.items()
}
{k: value.get(k, -1) for k in arr} will make sure that your keys are in the same order as you defined in the arr list.
A side note on the order of keys in dictionary.
Dictionaries preserve insertion order. Note that updating a key does
not affect the order. Keys added after deletion are inserted at the
end.
Changed in version 3.7: Dictionary order is guaranteed to be insertion
order. This behavior was an implementation detail of CPython from 3.6.
Please do not make a variable called dict, rename it to dct or something since dict it is a reserved python internal.
As for your question: just iterate through your dct and add the missing keys using setdefault:
arr = ['Adam', 'Ben', 'Chris', 'Dean', 'Flower']
dct = {
'abc': {'Dean': 1, 'Adam':0, 'Chris':1},
'def': {'Flower':0, 'Ben':1, 'Dean':0}
}
def add_dict_keys(dct, arr):
for key in arr:
dct.setdefault(key, -1)
return dct
for k, v in dct.items():
add_dict_keys(v, arr)
print(dct) # has updated values

Creating Dictionaries from Lists inside of Dictionaries

I'm quite new to Python and I have been stumped by a seemingly simple task.
In part of my program, I would like to create Secondary Dictionaries from the values inside of lists, of which they are values of a Primary Dictionary.
I would also like to default those values to 0
For the sake of simplicity, the Primary Dictionary looks something like this:
primaryDict = {'list_a':['apple', 'orange'], 'list_b':['car', 'bus']}
What I would like my result to be is something like:
{'list_a':[{'apple':0}, {'orange':0}], 'list_b':[{'car':0}, {'bus':0}]}
I understand the process should be to iterate through each list in the primaryDict, then iterate through the items in the list and then assign them as Dictionaries.
I've tried many variations of "for" loops all looking similar to:
for listKey in primaryDict:
for word in listKey:
{word:0 for word in listKey}
I've also tried some methods of combining Dictionary and List comprehension,
but when I try to index and print the Dictionaries with, for example:
print(primaryDict['list_a']['apple'])
I get the "TypeError: list indices must be integers or slices, not str", which I interpret that my 'apple' is not actually a Dictionary, but still a string in a list. I tested that by replacing 'apple' with 0 and it just returns 'apple', proving it true.
I would like help with regards to:
-Whether or not the values in my list are assigned as Dictionaries with value '0'
or
-Whether the mistake is in my indexing (in the loop or the print function), and what I am mistaken with
or
-Everything I've done won't get me the desired outcome and I should attempt a different approach
Thanks
Here is a dict comprehension that works:
{k: [{v: 0} for v in vs] for k, vs in primaryDict.items()}
There are two problems with your current code. First, you are trying to iterate over listKey, which is a string. This produces a sequence of characters.
Second, you should use something like
[{word: 0} for word in words]
in place of
{word:0 for word in listKey}
You are close. The main issue is the way you iterate your dictionary, and the fact you do not append or assign your sub-dictionaries to any variable.
This is one solution using only for loops and list.append.
d = {}
for k, v in primaryDict.items():
d[k] = []
for w in v:
d[k].append({w: 0})
{'list_a': [{'apple': 0}, {'orange': 0}],
'list_b': [{'car': 0}, {'bus': 0}]}
A more Pythonic solution is to use a single list comprehension.
d = {k: [{w: 0} for w in v] for k, v in primaryDict.items()}
If you are using your dictionary for counting, which seems to be the implication, an even more Pythonic solution is to use collections.Counter:
from collections import Counter
d = {k: Counter(dict.fromkeys(v, 0)) for k, v in primaryDict.items()}
{'list_a': Counter({'apple': 0, 'orange': 0}),
'list_b': Counter({'bus': 0, 'car': 0})}
There are specific benefits attached to collections.Counter relative to normal dictionaries.
You can get the data structure that you desire via:
primaryDict = {'list_a':['apple', 'orange'], 'list_b':['car', 'bus']}
for k, v in primaryDict.items():
primaryDict[k] = [{e: 0} for e in v]
# primaryDict
{'list_b': [{'car': 0}, {'bus': 0}], 'list_a': [{'apple': 0}, {'orange': 0}]}
But the correct nested access would be:
print(primaryDict['list_a'][0]['apple']) # note the 0
If you actually want primaryDict['list_a']['apple'] to work, do instead
for k, v in primaryDict.items():
primaryDict[k] = {e: 0 for e in v}
# primaryDict
{'list_b': {'car': 0, 'bus': 0}, 'list_a': {'orange': 0, 'apple': 0}}
primaryDict = {'list_a':['apple', 'orange'], 'list_b':['car', 'bus']}
for listKey in primaryDict:
primaryDict[i] = [{word:0} for word in primaryDict[listKey]]
print(primaryDict)
Output:
{'list_a':[{'apple':0}, {'orange':0}], 'list_b':[{'car':0}, {'bus':0}]}
Hope this helps!
#qqc1037, I checked and updated your code to make it working. I have mentioned the problem with your code as comments. Finally, I have also added one more example using list comprehension, map() & lambda function.
import json
secondaryDict = {}
for listKey in primaryDict:
new_list = [] # You did not define any temporary list
for word in primaryDict [listKey]: # You forgot to use key that refers the list
new_list.append( {word:0}) # Here you forgot to append to list
secondaryDict2.update({listKey: new_list}) # Finally, you forgot to update the secondary dictionary
# Pretty printing dictionary
print(json.dumps(secondaryDict, indent=4));
"""
{
"list_a": [
{
"apple": 0
},
{
"orange": 0
}
],
"list_b": [
{
"car": 0
},
{
"bus": 0
}
]
}
"""
Another example: Using list comprehension, map(), lambda function
# Using Python 3.5.2
import json
primaryDict = {'list_a':['apple', 'orange'], 'list_b':['car', 'bus']}
secondaryDict = dict(map(lambda key: (key, [{item:0} for item in primaryDict[key]]), list(primaryDict) ))
# Pretty printing secondary dictionary
print(json.dumps(secondaryDict, indent=4))
"""
{
"list_a": [
{
"apple": 0
},
{
"orange": 0
}
],
"list_b": [
{
"car": 0
},
{
"bus": 0
}
]
}
"""

Iterating JSON structure of list object and finding next keys

I have a Json list and I want to print all the keys from a given key till the end of dictionary. But the code I wrote is very complex. How to do it with less complexity ?
I'm using Python 3
dictionary = [{"a": "1"}, {"b": "2"}, {"c": "3"}, {"d": "4"}]
try:
for token in dictionary:
if "b" in list(token.keys())[0]:
new_dict = dictionary[len(list(token.keys())[0]):]
for i in new_dict:
print(new_dict[len(list(i.keys())[0]):])
break
else:
print("Inception")
except Exception as error:
print(str(error))
DESIRED
Input: b
Output: c, d
My Output:
Inception
[{'c': '3'}, {'d': '4'}]
[{'c': '3'}, {'d': '4'}]
[{'c': '3'}, {'d': '4'}]
Use itertools.dropwhile() to skip all dictionaries that don't have a 'b' key:
from itertools import dropwhile
filtered = dropwhile(lambda t: 'b' not in t, dictionary)
next(filtered) # skip the dictionary with `b` in it.
for token in filtered:
print(token)
This prints all dictionaries after the first. If you only need to print their keys, do so explicitly:
filtered = dropwhile(lambda t: 'b' not in t, dictionary)
next(filtered) # skip the dictionary with `b` in it.
for token in filtered:
print(*token, sep='\n')
This prints the keys on separate lines; if there is just one key, then that's all that'll be printed for each token dictionary.)
As a side note: you really do not want to use list(dict.keys())[0]. Before Python 3.6, dictionaries have no set order (instead being subject to insertion and deletion history and the current random hash seed), so if you have more than one key what value you'll get is a gamble. And all you want to do is see if a key is present, so use a key in dictobject membership test.
To get the first key out of each dictionary, I'd use next(iter(dictobject)), avoiding creating a list:
first_key = next(iter(dictobject))
I'd only use this if I had single-key dictionaries. I'd also avoid using dictionaries for such a scenario; perhaps you really wanted to use an ordered dictionary instead (in Python < 3.6, use collections.OrderedDict(), otherwise use the regular dict type).
This is one way. The idea is to find the index of the dictionary with desired key. Then filter your list accordingly.
keys = [next(iter(x)) for x in dictionary]
res = keys[keys.index('b')+1:]
# ['c', 'd']
You can re-write your code as follows for your desired result.
found = False
for data in dictionary:
if found:
print(list(data.keys())[0])
if 'b' in data.keys():
found = True

Categories