how to replace a key in dict python for loop - python

d={"given_age":"30","given_weight":"160","given_height":6}
want to remove "given_" from each of the key,
for key,value in d.items():
new_key=re.sub(r'given_','',key)
if new_key!=key:
d[new_key]=d.pop(key)
getting below error, my intention is to change the key only, why does it complain?
RuntimeError: dictionary keys changed during iteration

It is best not to modify collections when iterating over them. Use a dict comprehension here instead.
res = {re.sub('given_','',k) : v for k, v in d.items()}

You can also use str.replace() with dict comprehensiomn
d={"given_age":"30","given_weight":"160","given_height":6}
{key.replace('given_', '') : value for key, value in d.items()}
#{'age': '30', 'weight': '160', 'height': 6}
Edit as suggested by #CrazyChucky
{key.removeprefix('given_') : value for key, value in d.items()}
#{'age': '30', 'weight': '160', 'height': 6}

If you need to do this "in-place" and only change the keys that have the "given_" prefix, you could use the update method:
d.update((k[6:],d.pop(k)) for k in d if k.startswith("given_"))

Related

is it possible to reverse a dictionary in python using dictionary comprehension

I want to reverse dictionary key, value pairs using a dictionary comprehension, but if the new dictionary has more than one value for a key then it is getting replaced with the last value.
Is it possible to append to the values in the new dictionary if a key is repeated, using a comprehension?
Input:
test_di = {'a':'1', 'b':'2', 'c':'3', 'd':'2'}
Code:
{v:k for k,v in test_di.items()}
Output of this code:
{'1': 'a', '3': 'c', '2': 'd'}
Desired output:
{'1': ['a'], '3': ['c'], '2': ['b','d']}
It's not possible to do it in a reasonable way (i.e. O(N) time) with a dictionary comprehension. The comprehension simply can't handle duplicated values.
However, it's quite easy with a regular loop:
d = {}
for key, value in old_d.items():
d.setdefault(value, []).append(key)
A defaultdict would be the most efficient approach:
from collections import defaultdict
test_di = {'a':'1', 'b':'2', 'c':'3', 'd':'2'}
d = defaultdict(list)
for v,k in test_di.items():
d[k].append(v)
print(d)
Your question is confusing, but it sounds like you want to store multiple values at a single key in a dictionary.
This is not possible, you may want to look at storing a dictionary of lists.
You can use an OrderedDict and reverse the keys. A normal dict does not keep track of the order of the keys.
from collections import OrderedDict
dict1 = OrderedDict([('Name', 'Jon'), ('Race', 'Latino'), ('Job', 'Nurse')])
reversed_dict1 = OrderedDict([(key, dict1.get(key)) for key in reversed(dict1)])
Yes, it is possible (but it’s not the most efficient solution):
d = {'a':'1', 'b':'2', 'c':'3', 'd':'2'}
{v1: [k1 for k1, v2 in d.items() if v1 == v2] for v1 in d.values()}
# {'1': ['a'], '2': ['b', 'd'], '3': ['c']}

Converting Dict Keys and Searching Them

I have a dict that's like
dict1 = {'Lou': ['Male', '15', '2'],'Jen':['Female','10','3']...and more}
Im trying to search for values greater than 14 in the 2nd part of the list and then print out the key/value. I understand that I have to convert the strings to an integer and I believe I have to iterate by doing a dict1.values method however I'm unsure of how to specify the 2nd value in the list.
You can use dict1.items to iterate through key and values at the same time:
for key, value in dict1.items():
if int(value[1]) > 14:
print key, value
For each value you get the second part with value[1], you convert it to an integer with int and then you perform your check. When the check is successful, we print both key and value, as we have access to them.
You could use dict_comprehension.
>>> dict1 = {'Lou': ['Male', '15', '2'],'Jen':['Female','10','3']}
>>> {x:y for x,y in dict1.items() if int(y[1]) > 14}
{'Lou': ['Male', '15', '2']}
you need to use dict.items it will give you a tuple containing key/value pair.
Using filter and lambda:
>>> my_dict = {'Lou': ['Male', '15', '2'],'Jen':['Female','10','3']}
>>> filter(lambda x:int(x[1][1])>14, my_dict.items())
[('Lou', ['Male', '15', '2'])]
using Keys:
>>> {x:my_dict[x] for x in my_dict if int(my_dict[x][1])>14}
{'Lou': ['Male', '15', '2']}

Inverse order of dictionary values

I have a python dictionary like the following:
myDict = {'cb_rdbu_4': [['202', '0', '32'], ['244', '165', '130'], ['146', '197', '222'], ['5', '113', '176']]}
I like to inverse the order of the elements in the list. So for instance for the first key value list I like to have the following order:
'cb_rdbu_4': [['5', '113', '176'], ['146', '197', '222'], ['244', '165', '130'], ['202', '0', '32']]
How do I do that?
new_dict = dict([(key,reversed(value)) for key,value in myDict.items()])
or if you want to edit it in place
for key in myDict:
myDict[key] = reversed(myDict[key])
instead of reversed(value) you can do value[::-1]
This is a easy one.
for key, val in myDict.items():
myDict[key] = myDict[key][::-1]
You want to reverse() all the values() of the dictionary:
for seq in the_dict.values():
seq.reverse()
If you are using python2 you may replace values() with itervalues() for better performance.
Note that this mutates the original dictionary. If you want to also preserve the original dictionary, you can create a new one with a dictionary comprehension:
new_dict = {key: list(reversed(value)) for key, value in original.items()}
Or:
new_dict = {key: value[::-1] for key, value in original.items()}
If you are using an older version of python that doesn't provide dictionary comprehension you can use:
new_dict = dict((key, list(reversed(value))) for key, value in original.items())

Common items between all the keys of a dictionary

I have a dictionary of "259136 keys" and each of those keys, have 1 or more than one values.
My objective is "to find keys that have at least one value common with another key in the list of keys?"
I have tried different ways to deal with this problem but I was looking for a faster solution. I tried
for each key compare with the 259135 keys to check the above condition
reversing the dictionary from key value to value key, so now the value becomes key and this way I will have two dictionaries and I can go to first one and based on the values in the first one pull out all the values from the second one.
Use a dict of sets:
d={ 'k1': [1,2,3],
'k2': [2],
'k3': [10],
'k4': [3,2]
}
com_keys={}
for k, v in d.items():
for e in v:
com_keys.setdefault(e, set()).add(k)
print com_keys
# {1: set(['k1']), 10: set(['k3']), 3: set(['k1', 'k4']), 2: set(['k2', 'k1', 'k4'])}
Then if you only want the ones that have more than one key in common, just filter with a dict comprehension (or the like for older Pythons):
>>> {k:v for k,v in com_keys.items() if len(v)>1 }
{2: set(['k2', 'k1', 'k4']), 3: set(['k1', 'k4'])}
It get a little more challenging if your dict is a non-homogenous combination of containers that support iteration (lists, tuples, etc) with 'single items' that either do not support iteration (ints, floats) or things that you do not want to iterate with a for loop (strings, unicode, other dicts, etc)
For example, assume you have a combination of lists and 'single items' that are ints and strings:
import collections
d={ 'k1': [1,2,3],
'k2': 2,
'k3': [10],
'k4': [3,2],
'k5': 'string',
'k6': ['string',2]
}
com_keys={}
for k, v in d.items():
if not isinstance(v, basestring) and isinstance(v, collections.Iterable):
for e in v:
com_keys.setdefault(e, set()).add(k)
else:
com_keys.setdefault(v, set()).add(k)
print com_keys
# {1: set(['k1']), 10: set(['k3']), 3: set(['k1', 'k4']), 2: set(['k2', 'k1', 'k6', 'k4']), 'string': set(['k6', 'k5'])}
print {k:v for k,v in com_keys.items() if len(v)>1 }
# {2: set(['k2', 'k1', 'k6', 'k4']), 3: set(['k1', 'k4']), 'string': set(['k6', 'k5'])}

remove the keys which has blank values

how to remove keys in a dict which do not have any value. I have a dict as :
d = {'CB': '', 'CA': [-7.5269999504089355, -2.2330000400543213, 6.748000144958496], 'C': [-8.081000328063965, -3.619999885559082, 6.406000137329102], 'N': [-6.626999855041504, -2.318000078201294, 7.9029998779296875], 'H':''}
I want to remove keys which values are blank. I need output as :
d = {'CA': [-7.5269999504089355, -2.2330000400543213, 6.748000144958496], 'C': [-8.081000328063965, -3.619999885559082, 6.406000137329102], 'N': [-6.626999855041504, -2.318000078201294, 7.9029998779296875]}
how to do this?
Use a dict-comprehension:
>>> {k:v for k, v in d.items() if v != ''}
{'N': [-6.626999855041504, -2.318000078201294, 7.9029998779296875], 'CA': [-7.5269999504089355, -2.2330000400543213, 6.748000144958496], 'C': [-8.081000328063965, -3.619999885559082, 6.406000137329102]}
If by empty you meant any falsy value then use just if v.
If you want to modify the original dict itself(this will affect all the references to the dict object):
for k, v in d.items():
if not v: del d[k]
>> {key:value for key, value in d.items() if value}
If you really need to do this in one-line:
for k in [k for k,v in d.iteritems() if not v]: del d[k]
This is ugly. It makes a list of all of the keys in d that have a "blank" value and then iterates over this list removing the keys from d (to avoid the unsafe removal of items from dictionary during iteration).
I'd suggest that three lines would be more readable:
blanks = [k for k,v in d.iteritems() if not v]
for k in blanks:
del d[k]
If making a fresh dict is acceptable, use a dict comprehension:
d2 = {k:v for k,v in d.iteritems() if not v}

Categories