Preventing Python dictionary from mutating - python

I need to write a function that takes a a dictionary and a string as input, and returns the updated dictionary as follows:
>>> dct = {'a':1, 'q':1, 'l':2, 'm':1, 'u':1, 'i':1}
>>> updateHand(dct, 'quail')
returns {'a':0, 'q':0, 'l':1, 'm':1, 'u':0, 'i':0}
I'm writing the following code, but I don't know somehow it mutates the dictionary ( it shouldn't ).
def updateHand(dct, s)
for char in s :
dct[char] = dct.get(char,0) - 1
return dct
I get the following message, when I run the above example:
Original dct was {'a': 1, 'i': 1, 'm': 1, 'l': 2, 'q': 1, 'u': 1}
but implementation of updateHand mutated the original hand!
Now the dct looks like this: {'a': 0, 'q': 0, 'u': 0, 'i': 0, 'm': 1, 'l': 1}
What is meant by mutating a dictionary ? And how do I overcome it ?
And on the side note, doesn't Python maintain random ordering of elements, like Java ?

Use the copy of the original dictionary using dict.copy:
def updateHand(dct, s)
dct = dct.copy() # <----
for char in s :
dct[char] = dct.get(char,0) - 1
return dct
What is meant by mutating a dictionary ?
The code changes the dictionary passed instead of returning new one.
And on the side note, doesn't Python maintain random ordering of elements, like Java ?
The insertion order is not maintained in dictionary.

Related

Merge 2 dictionaries based on specific features

With 2 json file I am trying to merge certain features of one into the other. I converted the json into dictionaries I am trying to merge features from 1 dictionary into another. However I want specific features of one dictionary to merege with the other but not overwrite the initial values
Dictionary A: [{a:1,b:2,f:10},{a:2,b:4,f:10}]
Dictionary B: [{f:1,g:1,k:1},{f:2,g:2,k:1}]
Desired:
Dictionary C:[{a:1,b:2,f:10,g:1,k:1},{a:2,b:4,f:10,g:2,k:1}]
Loop through all dictionaries simultaneously
for x,y in zip(A,B):
x["g"]= y["g"]
x["k"]= y["k"]
You can iterate using zip then combine the dictionaries and filter out the keys that you don't want, you can use comprehension:
# Python 3.9+
>>> [y|x for x,y in zip(A, B)]
# output:
[{'f': 10, 'g': 1, 'k': 1, 'a': 1, 'b': 2},
{'f': 10, 'g': 2, 'k': 1, 'a': 2, 'b': 4}]
This will preserve the order and not overwrite any duplicate keys in A.
lst_a = [{'a':1,'b':2,'f':10},{'a':2,'b':4,'f':10}]
lst_b = [{'f':1,'g':1,'k':1},{'f':2,'g':2,'k':1}]
lst_c = []
for dict_a,dict_b in zip(lst_a,lst_b):
dict_b = {k:v for k,v in dict_b.items() if k not in dict_a}
lst_c.append(dict_a | dict_b)
print(lst_c)

Return values from one dictionary by comparing keys from another dictionary

I have two dictionaries and I want to get the values of the first dictionary for the keys of the second. Both the dictionaries have the same keys but in different order.
For example:
dict1={'a':1,'b':1,'c':0,'d':0,'e':1,'f':0,'g':1}
This is the first dictionary. And the second dictionary is:
dict2={'c':3,'b':2,'a':1,'d':1,'e':0,'g':0,'f':0}
I want to get the values corresponding to the first dictionary but in the order of keys of the second dictionary.
So the output should be like this:
dict3={'c':0,'b':1,'a':1,'d':0,'e':1,'g':1,'f':0}
Is there any way to do that?
If you have you have Python 3.7+ you can use this:
dict1={'a':1,'b':1,'c':0,'d':0,'e':1,'f':0,'g':1}
dict2={'c':3,'b':2,'a':1,'d':1,'e':0,'g':0,'f':0}
dict3 = {k: dict1[k] for k in dict2.keys()}
print(dict3)
> {'c': 0, 'b': 1, 'a': 1, 'd': 0, 'e': 1, 'g': 1, 'f': 0}
What’s New In Python 3.7
the insertion-order preservation nature of dict objects has been declared to be an official part of the Python language spec.
Is this what you meant?
dict3 = {key:dict1[key] for key in dict2.keys()}
Tried on python 3.9.

Keeping the same order for a dictionary

I need to write a function called updateHand(hand, word) which does this:
Assumes that 'hand' has all the letters in word. In other words, this
assumes that however many times a letter appears in 'word', 'hand' has
at least as many of that letter in it.
Updates the hand: uses up the letters in the given word and returns
the new hand, without those letters in it.
Has no side effects: does not modify hand.
word: string hand: dictionary (string -> int) returns: dictionary
(string -> int)
I wrote the code and everything is working except the fact that when 'hand' is returned, it is not in the same order:
updateHand({'u': 1, 'q': 1, 'a': 1, 'm': 1, 'l': 2, 'i': 1}, 'quail')
{'u': 0, 'i': 0, 'm': 1, 'a': 0, 'l': 1, 'q': 0}
Could someone give me the solution or even just a hint to this problem because I don't understand...
A dict will not returns the items by insertion order.
What you need is OrderedDict:
from collections import OrderedDict
my_dict = OrderedDict()
my_dict['a'] = 1
...
This concerns only python version < 3.6. From python 3.6, the insertion order is kept.

How to create a dict out of 2 dict's that already exist in Python 3

How can I create a new dictionary out of 2 dictionaries that I already have created?
It should look like this:
d1 = {'a': 2, 'b': 3}
d2 = {'s': 4, 'k': 5}
The keys from d1 and the values from d2 have to be in d3.
d3= {'a': 4, 'b': 5}
Is there an operation that combines the keys from one dict and the values from another dict to create a new dictionary.
It can be done several ways. If you wish to use a loop you try this:
for i in range(len(d1.keys())):
d1[d1.keys()[i]]=d2.values()[i]
Make sure the structure remains same of both the dictionaries.
Dictionaries do not have ordering, then u can use OrderedDict or tuple and zip for union.
Example
from collections import OrderedDict
d1 = {'a': 2, 'b':3}
d2 = {'s': 4, 'k': 5}
d1 = OrderedDict(d1)
d2 = OrderedDict(d2)
for value_d1,value_d2 in zip(d1.values(),d2.values()):
new_value = value_d1 + value_d2
Since you were not very specific in your problem, I have no way of trying to show something more elegant.
d1={'a':2,'b':3}
d2={'s':4,'k':5}
k=list(d1.keys())
v=list(d2.values())
d3={}
for i in range(len(k)):
d3[k[i]]=v[i]
Use check before the loop to make sure that number of keys equals number of values to avoid getting exceptions.

Remove key from dictionary in Python returning new dictionary

I have a dictionary
d = {'a':1, 'b':2, 'c':3}
I need to remove a key, say c and return the dictionary without that key in one function call
{'a':1, 'b':2}
d.pop('c') will return the key value - 3 - instead of the dictionary.
I am going to need one function solution if it exists, as this will go into comprehensions
How about this:
{i:d[i] for i in d if i!='c'}
It's called Dictionary Comprehensions and it's available since Python 2.7.
or if you are using Python older than 2.7:
dict((i,d[i]) for i in d if i!='c')
Why not roll your own? This will likely be faster than creating a new one using dictionary comprehensions:
def without(d, key):
new_d = d.copy()
new_d.pop(key)
return new_d
If you need an expression that does this (so you can use it in a lambda or comprehension) then you can use this little hack trick: create a tuple with the dictionary and the popped element, and then get the original item back out of the tuple:
(foo, foo.pop(x))[0]
For example:
ds = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}]
[(d, d.pop('c'))[0] for d in ds]
assert ds == [{'a': 1, 'b': 2}, {'a': 4, 'b': 5}]
Note that this actually modifies the original dictionary, so despite being a comprehension, it's not purely functional.
When you invoke pop the original dictionary is modified in place.
You can return that one from your function.
>>> a = {'foo': 1, 'bar': 2}
>>> a.pop('foo')
1
>>> a
{'bar': 2}
solution from me
item = dict({"A": 1, "B": 3, "C": 4})
print(item)
{'A': 1, 'B': 3, 'C': 4}
new_dict = (lambda d: d.pop('C') and d)(item)
print(new_dict)
{'A': 1, 'B': 3}
this will work,
(lambda dict_,key_:dict_.pop(key_,True) and dict_)({1:1},1)
EDIT
this will drop the key if exist in the dictionary and will return the dictionary without the key,value pair
in python there are functions that alter an object in place, and returns a value instead of the altered object, {}.pop function is an example.
we can use a lambda function as in the example, or more generic below
(lambda func:obj:(func(obj) and False) or obj)
to alter this behavior, and get a the expected behavior.

Categories