Looping over nested dictionary and delete if condition is not met (python) - python

I have a list of nested dictionaries:
[{'a': 1,
'b': 'string',
'c': [{'key1': 80,
'key2': 'string',
'key3': 4033},
{'key1': 324,
'key2': 'string',
'key3': 4034,
'key4': 1}]},
{'a': 1,
'b': 'string',
'c': [{'key1': 80,
'key2': 'string',
'key3': 4033},
{'key1': 324,
'key2': 'string',
'key3': 4034,
'key4': 1,
'key5': 2}]}]
Please not that the values of key c is a list of dictionaries again.
Now I want to filter out from this list all dictionaries with key c, that do not contain key1, key2, key3 & key4.
I thought of looping first over the first, second, and so on dict in the list, and then looping over the nested dicts that have c as a key. Then, if the dict inside c does not meet my requirement, I delete it.
Therefore my code would be:
for j in range(len(mydict)):
for i in range(len(mydict[j]["c"])):
if not all (k in mydict[j]["c"][i] for k in ("key1", "key2", "key3", "key4")):
del(mydict[j]["c"][i])
But I am getting a IndexError: list index out of range error. Where is my mistake?
My desired output would be:
[{'a': 1,
'b': 'string',
'c': [{'key1': 324,
'key2': 'string',
'key3': 4034,
'key4': 1}]},
{'a': 1,
'b': 'string',
'c': [{'key1': 324,
'key2': 'string',
'key3': 4034,
'key4': 1,
'key5': 2}]}]

The problem is that with for i in range(len(mydict[j]["c"])): you are iterating the lists in the dict while at the same time removing from those lists. Instead, you can replace the inner loop with a list comprehension:
for d in mydict:
d['c'] = [d2 for d2 in d['c']
if all(k in d2 for k in ("key1", "key2", "key3", "key4"))]

Just to have another option:
keep = {'key1', 'key2', 'key3', 'key4'}
for h in mydict:
h['c'] = [ e for e in h['c'] if len(keep - set(e.keys())) == 0 ]

If you wanted another perspective on it:
def remove_keys(mydict):
mydict2 = mydict
keys = ['key1', 'key2', 'key3', 'key4']
for xIndex, x in enumerate(mydict):
for yIndex, y in enumerate(x['c']):
if not all(key in y.keys() for key in keys):
del mydict2[xIndex]['c'][yIndex]
return mydict2
Returns a new dictionary with the modifications.

Related

To convert a dict (with list of keys and values) into list of dict

I have a dict with a list of keys, and the values are stored separate in a list of lists:
obj = {
'keys': ['key1', 'key2', 'key3'],
'items': [['value1', 'value2', 'value3'], ['value4', 'value5', 'value6'], ['value7', 'value8', 'value9']]
}
The desired output is to 'merge' them into a list of dict like this:
[
{'key1': 'value1', 'key2': 'value2', 'key3': 'value3'},
{'key1': 'value4', 'key2': 'value5', 'key3': 'value6'},
{'key1': 'value7', 'key2': 'value8', 'key3': 'value9'}
]
I have tried this direct approach
result = []
for item in obj['items']:
result.append(dict(zip(obj['keys'], item)))
and also shortened it to this
[dict(zip(obj['keys'], item)) for item in obj['items']]
Are there other alternatives to achieve the desired output?
And may I know what is the name of this 'merge' manipulation?
You can use pandas:
import pandas as pd
obj = {
'keys': ['key1', 'key2', 'key3'],
'items': [['value1', 'value2', 'value3'], ['value4', 'value5', 'value6'], ['value7', 'value8', 'value9']]
}
df = pd.DataFrame(obj['items'], columns=obj['keys'])
df.to_dict(orient='records')
result:
[{'key1': 'value1', 'key2': 'value2', 'key3': 'value3'},
{'key1': 'value4', 'key2': 'value5', 'key3': 'value6'},
{'key1': 'value7', 'key2': 'value8', 'key3': 'value9'}]
[ dict(zip(obj['keys'], item)) for item in obj['items'] ]
Your final line has a combination of these components:
list comprehension, ie, [ function(x) for x in list_x ]
zipping of 2 lists, ie, zip(list1, list2)
Perhaps these are the names of the 'merge' manipulation you are looking for?

Python sort list of dicts with lists inside

I have the following list structure:
[
{'key1': 'value1',
'key2': [['mike', 'simmons', '54:17:47']],
'key3': 19390},
{'key1': 'value1',
'key2': [['snart', 'simmons', '60:12:47']],
'key3': 19390}
]
I would like to sort this list by the second index of the key2 key ( I mean, by those 60:12:47 numbers)
I haven't found a standard way of doing this..
Thanks!
Here is one way, assuming you want your values sorted as strings.
lst = [{'key1': 'value1', 'key2': [['snart', 'simmons', '60:12:47']], 'key3': 19390},
{'key1': 'value1', 'key2': [['mike', 'simmons', '54:17:47']], 'key3': 19390}]
res = sorted(lst, key=lambda x: x['key2'][0][2])
# [{'key1': 'value1', 'key2': [['mike', 'simmons', '54:17:47']], 'key3': 19390},
# {'key1': 'value1', 'key2': [['snart', 'simmons', '60:12:47']], 'key3': 19390}]
Use sorted with a comparator that uses that value:
sorted_list = sorted(my_list, key=lambda d: d['key2'][0][2])

How to duplicate dictionary with 0 values

What I can do:
dict1 = {'key1':0, 'key2':10, 'key3':110}
dict2 = dict(dict1)
for key in dict2:
dict2[key] = 0
print(dict2) # {'key1':0, 'key2':0, 'key3':0}
Is there a simple way to do that?
Simplest, using dict comprehension :
>>> {k:0 for k in dict1}
# driver values :
IN : dict1 = {'key1':0, 'key2':10, 'key3':110}
OUT : {'key1':0, 'key2':0, 'key3':0}
Yes. Use dict.fromkeys:
>>> dict1 = {'key1':0, 'key2':10, 'key3':110}
>>> dict.fromkeys(dict1, 0)
{'key1': 0, 'key2': 0, 'key3': 0}
Be careful, though, if your fill-value is a mutable object, this will mean every value will be the same instance of that mutable object, e.g.:
>>> new_dict = dict.fromkeys(dict1, [])
>>> new_dict
{'key1': [], 'key2': [], 'key3': []}
>>> new_dict['key1'].append('foo')
>>> new_dict
{'key1': ['foo'], 'key2': ['foo'], 'key3': ['foo']}
dict1 = {'key1':0, 'key2':10, 'key3':110}
dict2 = dict((i,0) for i in dict1)
Result:
{'key3': 0, 'key2': 0, 'key1': 0}

New dictionary from comprehension with setten keys

I've got two dictionaries:
dict1 = {'id': 1001, 'text': 'some text 1', 'key1': 11, 'key2': 12}
dict2 = {'id': 1002, 'text': 'some text 2', 'key1': 1, 'key2': 2}
And I want to get something like this, keep 'id' from' dict1 and subtract 'key1' and 'key2':
dict3 = {'id': 1001, 'key1': 10, 'key2': 10 }
I've tried as following:
dict3 = {key: dict1[key] - dict2.get(key, 0) for key in ['key1', 'key2']}
but I don't know how to keep original 'id'.
Your code is fine but I would use the dict-comprehension to update the dict and not create it. That way, I could apply it to a dict that is already initialized with the desired 'id' value.
dict1 = {'id': 1001, 'text': 'some text 1', 'key1': 11, 'key2': 12}
dict2 = {'id': 1002, 'text': 'some text 2', 'key1': 1, 'key2': 2}
dict3 = {'id': dict1['id']} # initialize it first
dict3.update({key: dict1[key] - dict2.get(key, 0) for key in ['key1', 'key2']})
print(dict3) # {'id': 1001, 'key1': 10, 'key2': 10}
Since you have only two dicts with few element, its far more easier getting your required dict manually.
>>> d3 = { 'id':dict1['id'] , 'key1':dict1['key1']-dict2['key1'] ,
'key2':dict1['key2']-dict2['key2'] }
>>> d3
=> {'id': 1001, 'key1': 10, 'key2': 10}

How can I merge two nested dictionaries together?

I've got two nested dictionaries that have overlapping keys at the first level, but different keys at the second level. I want to merge them, so that the new dictionary has all of the keys.
A = {'id1': {'key1': 1, 'key2': 2 }, 'id2':{'key1': 3, 'key2': 4 }}
B = {'id1': {'key3': 5}, 'id2': {'key3': 6}}
The result should be
A_B = {'id1': {'key1': 1, 'key2': 2, 'key3': 5}, 'id2':{'key1': 3, 'key2': 4, 'key3': 6}}
I know that I could do a for loop
for key in A:
A[key].update(B[key])
But I would like to know if there is a cleaner solution.
You could merge them in a dictionary comprehension:
A_B = {k: dict(A.get(k, {}), **B.get(k, {})) for k in A.viewkeys() | B.viewkeys()}
This uses the Python 2 dictionary keys view object; in Python 3, use dict.keys() instead of dict.viewkeys().
This'll merge all keys even if they are only present in one or the other of the dictionaries.
Demo with your input:
>>> A = {'id1': {'key1': 1, 'key2': 2 }, 'id2':{'key1': 3, 'key2': 4 }}
>>> B = {'id1': {'key3': 5}, 'id2': {'key3': 6}}
>>> {k: dict(A.get(k, {}), **B.get(k, {})) for k in A.viewkeys() | B.viewkeys()}
{'id2': {'key3': 6, 'key2': 4, 'key1': 3}, 'id1': {'key3': 5, 'key2': 2, 'key1': 1}}
or with input with more varied keys:
>>> C = {'foo': {'spam': 1, 'ham': 2}, 'bar': {'spam': 43, 'eggs': 81}}
>>> D = {'baz': {'vikings': 'singing'}, 'bar': {'monty': 'python'}}
>>> {k: dict(C.get(k, {}), **D.get(k, {})) for k in C.viewkeys() | D.viewkeys()}
{'bar': {'eggs': 81, 'monty': 'python', 'spam': 43}, 'foo': {'ham': 2, 'spam': 1}, 'baz': {'vikings': 'singing'}}
Iterate dictionary B
Check if key from the B is present in the A- Exception Handling
If yes, then Update respective value of A by B.
If Not, then Add New Key with value in A
code:
>>> A = {'id1': {'key1': 1, 'key2': 2 }, 'id2':{'key1': 3, 'key2': 4 }}
>>> B = {'id1': {'key3': 5}, 'id2': {'key3': 6}}
>>> for i, j in B.items():
... if i in A:
... A[i].update(j)
... else:
... A[i] = j
...
>>> A
{'id2': {'key3': 6, 'key2': 4, 'key1': 3}, 'id1': {'key3': 5, 'key2': 2, 'key1': 1}}
>>>

Categories