Brief description of code:
The main code first makes a blank dictionary, which is passed on to my function. The function tallies how many of each number and updates the dictionary which is then returned. However when the function executes, it overwrites the input 'blank_dictionary' to be the same as the dictionary it returns ('new_dictionary'). Why does this happen? I want the 'dictionary' in the main code to remain blank throughout so that it can be reused.
def index_list(lst, blank_dictionary):
new_dictionary = blank_dictionary
for i in lst:
new_dictionary[i] += 1
return new_dictionary
number = 1
maximum = 3
numbers = range(1,maximum+1)
dictionary = {}
for i in numbers:
dictionary[i] = 0
print ('original blank dictionary', dictionary)
new_dictionary = index_list([3,3,3],dictionary)
print ('new dictionary which indexed the list', new_dictionary)
print ('should still be blank, but isnt', dictionary)
Outputs:
original blank dictionary {1: 0, 2: 0, 3: 0}
new dictionary which indexed the list {1: 0, 2: 0, 3: 3}
should still be blank, but isnt {1: 0, 2: 0, 3: 3}
Thanks very much
You are setting new_dictionary to the reference to blank_dictionary. Change the line to new_dictionary = dict(blank_dictionary) and you will be fine. Using the dict() constructor function will make a new new_dictionary and so blank_dictionary will not be modified.
You might want to investigate the defaultdict in the collections module. If you only need to count the number of times each element appears, consider collections.counter.
This behavior is not limited to dicts. In Python, any time you pass a mutable object to a function, the function operates on the original object, not a copy. This is not true for immutable objects like tuples and strings.
However in this case there is no reason to pass a blank dictionary to the function in the first place. The function can create a new dictionary and return it.
Related
I don't really understand the concept of python dictionary, can anyone help me? I want the program to have similar functionality as append in list python
d = {'key': ['value']}
print(d)
# {'key': ['value']}
d['key'] = ['mynewvalue']
print(d)
# {'key': ['mynewvalue']}
what I want the output of the program, either :
print(d)
#{'key': ['value'],'key': ['mynewvalue']}
or :
print(d)
#{'key': ['value','mynewvalue']}
Sure: first thing first, you can't have two identical keys in a dictionary. So:
{'key': 'myfirstvalue', 'key': 'mysecondvalue'}
wouldn't work. If a key has multiple values, then the key's value should be a list of values, like in your last option. Like in a real dictionary, you won't find, word: definition, word: another definition but word: a list of definitions.
In this regard, you could kind of think of a dictionary as a collection of variables - you can't assign two values to a variable except by assigning a list of values to variable.
x = 4
x = 5
is working code, but the first line is rendered meaningless. x is only equal to 5, not both 4 and 5. You could, however, say:
x = [4, 5]
I often use dictionaries for trees of data. For example, I'm working on a project involving counties for every state in the US. I have a dictionary with a key for each state, and the value of each key is another dictionary, with a key for each county, and the value for each of those dictionaries is another dictionary with the various data points for that county.
That said, you can interact with your dictionary just like you would with variables.
mylist = [1, 2, 3, 4]
mylist.append(5)
print(mylist)
will print:
[1,2,3,4,5]
But also:
mydict = {'mylist': [1,2,3,4]}
mydict['mylist'].append(5)
does the same thing.
mydict['mylist']
is the same as
mylist
in the first example. Both are equal to the list [1,2,3,4]
You cannot have same keys multiple times in a dict in python. The first output scenario you gave is invalid. The value of a dict can contain any data and in your case, it can be accessed and modified just as a list. You can modify the code as given below to get the output as desired in scenario number 2.
d = {'key': ['value']}
print(d)
# {'key': ['value']}
d['key'].append('mynewvalue')
print(d)
#{'key': ['value','mynewvalue']}
you can try it:
d = {'key': ['value']}
d['key'].append("mynewvalue")
print(d)
Output will be: {'key': ['value', 'mynewvalue']}
For the first implementation you want, I think you are violating the entire idea of dictionary, we can not have multiple keys with the same name.
For the second implementation you could write a function like this:
def updateDict(mydict,value):
mydict['key'].append(value)
This is the code:
def appd():
atho = []
data = {'snm':None}
for i in range(5):
data['snm'] = i
atho.append(data)
return atho
I expect that the result will be like this:
[{'snm': 0}, {'snm': 1}, {'snm': 2}, {'snm': 3}, {'snm': 4}]
but the result I got in python 3 platform is:
[{'snm': 4}, {'snm': 4}, {'snm': 4}, {'snm': 4}, {'snm': 4}]
How does that happen?
A dictionary cannot have identical keys. So, every time you are doing data['snm'] = i you are replacing the value. Also, your append adds the same dictionary every time, not a copy. So, you list does not have 5 dictionaries, it has 5 references to the same dictionary. And, when it changes, all positions of your list change.
Short fix: add a new dict every time
for i in range(5):
atho.append({'snm': i})
Dictionary cannot hold duplicate keys. If you try adding duplicates, the last added value is added to the key.
>>> d = {'a': 1}
>>> d['a'] = 2
>>> d['a'] = 3
>>> d
{'a': 3}
>>>
With data['snm'] = i, you are basically doing the same thing and this dictionary is being added to list using append.
To fix it, define data = {} inside your loop, so every time you create a new dictionary before appending.
def appd():
atho = []
for i in range(5):
data = {}
data['snm'] = i
atho.append(data)
return atho
print(appd())
You are inserting the same dictionary again and again, instead of inserting a new dictionary whose key is snm.
On each iteration of the range, you are updating the value of the dictionary, therefore it gets updated for all the elements in the list, because all of them point to the same dictionary instance.
You must create a new dictionary on each iteration and then insert it.
Try this:
def appd():
atho = []
for i in range(5):
atho.append({'snm':i})
return atho
If you reuse the same oject, again and again, you are simply updating it's contents. The trick is either to explicitly copy the object or create a new one. You cannot simply keep overriting the same key and expect different values
You are actually appending a reference to the original dictionary.
The result you are seeing is the last iteration of your loop updating the dictionary, and thus all its references in your list.
Using atho.append(data.copy()) will work.
I have a function to create a dictionary with specific keys, which accepts a parameter to specify what each key's "default" value should be.
def new_dict(entrys_default=0):
my_dict = {}
for k in ['a', 'b', 'c']:
my_dict[k] = entrys_default
return my_dict
The issue is that when I call it with new_dict(entrys_default=[]) so that each entry in the dictionary is created with a new empty list as its value, when I then update one entry with returned_dict['a'].append(123) then all entries are updated:
{'a': [123], 'b': [123], 'c': [123]}
This doesn't happen when using an integer, and I understand that it is because the entrys_default is immutable when it is an integer, but is a reference to the same list when it is a list or dictionary.
I want to be able to have this function work the same as it does for integer parameters with lists and dictionaries as entrys_default - i.e. each entry has its own list/dictionary - but want to keep the function flexible to also work for integers.
Can anyone please suggest the best way to go about this?
Do what collections.defaultdict does; instead of taking an "example" default value, take a function that returns the desired default value. Then call that function and use its return value to initialize each element of the dict being constructed.
def new_dict(make_default=int): # int() == 0
my_dict = {}
for k in ['a', 'b', 'c']:
my_dict[k] = make_default()
return my_dict
d = new_dict(list) # list() == [], but a distinct list each time it is called
d['a'].append(123)
assert d['a'] != d['b']
(I'm new to Python!)
Trying to figure out this homework question:
The function will takes as input two dictionaries, each mapping strings to integers. The function will return a dictionary that maps strings from the two input dictionaries to the sum of the integers in the two input dictionaries.
my idea was this:
def add(dicA,dicB):
dicA = {}
dicB = {}
newdictionary = dicA.update(dicB)
however, that brings back None.
In the professor's example:
print(add({'alice':10, 'Bob':3, 'Carlie':1}, {'alice':5, 'Bob':100, 'Carlie':1}))
the output is:
{'alice':15, 'Bob':103, 'Carlie':2}
My issue really is that I don't understand how to add up the values from each dictionaries. I know that the '+' is not supported with dictionaries. I'm not looking for anyone to do my homework for me, but any suggestions would be very much appreciated!
From the documentation:
update([other])
Update the dictionary with the key/value pairs from other, overwriting existing keys. Return None.
You don't want to replace key/value pairs, you want to add the values for similar keys. Go through each dictionary and add each value to the relevant key:
def add(dicA,dicB):
result = {}
for d in dicA, dicB:
for key in d:
result[key] = result.get(key, 0) + d[key]
return result
result.get(key, 0) will retrieve the value of an existing key or produce 0 if key is not yet present.
First of all, a.update(b) updates a in place, and returns None.
Secondly, a.update(b) wouldn't help you to sum the keys; it would just produce a dictionary with the resulting dictionary having all the key, value pairs from b:
>>> a = {'alice':10, 'Bob':3, 'Carlie':1}
>>> b = {'alice':5, 'Bob':100, 'Carlie':1}
>>> a.update(b)
>>> a
{'alice': 5, 'Carlie': 1, 'Bob': 100}
It'd be easiest to use collections.Counter to achieve the desired result. As a plus, it does support addition with +:
from collections import Counter
def add(dicA, dicB):
return dict(Counter(dicA) + Counter(dicB))
This produces the intended result:
>>> print(add({'alice':10, 'Bob':3, 'Carlie':1}, {'alice':5, 'Bob':100, 'Carlie':1}))
{'alice': 15, 'Carlie': 2, 'Bob': 103}
The following is not meant to be the most elegant solution, but to get a feeling on how to deal with dicts.
dictA = {'Alice':10, 'Bob':3, 'Carlie':1}
dictB = {'Alice':5, 'Bob':100, 'Carlie':1}
# how to iterate through a dictionary
for k,v in dictA.iteritems():
print k,v
# make a new dict to keep tally
newdict={}
for d in [dictA,dictB]: # go through a list that has your dictionaries
print d
for k,v in d.iteritems(): # go through each dictionary item
if not k in newdict.keys():
newdict[k]=v
else:
newdict[k]+=v
print newdict
Output:
Bob 3
Alice 10
Carlie 1
{'Bob': 3, 'Alice': 10, 'Carlie': 1}
{'Bob': 100, 'Alice': 5, 'Carlie': 1}
{'Bob': 103, 'Alice': 15, 'Carlie': 2}
def add(dicA,dicB):
You define a function that takes two arguments, dicA and dicB.
dicA = {}
dicB = {}
Then you assign an empty dictionary to both those variables, overwriting the dictionaries you passed to the function.
newdictionary = dicA.update(dicB)
Then you update dicA with the values from dicB, and assign the result to newdictionary. dict.update always returns None though.
And finally, you don’t return anything from the function, so it does not give you any results.
In order to combine those dictionaries, you actually need to use the values that were passed to it. Since dict.update mutates the dictionary it is called on, this would change one of those passed dictionaries, which we generally do not want to do. So instead, we use an empty dictionary, and then copy the values from both dictionaries into it:
def add (dicA, dicB):
newDictionary = {}
newDictionary.update(dicA)
newDictionary.update(dicB)
return newDictionary
If you want the values to sum up automatically, then use a Counter instead of a normal dictionary:
from collections import Counter
def add (dicA, dicB):
newDictionary = Counter()
newDictionary.update(dicA)
newDictionary.update(dicB)
return newDictionary
I suspect your professor wants to achieve this using more simple methods. But you can achieve this very easily using collections.Counter.
from collections import Counter
def add(a, b):
return dict(Counter(a) + Counter(b))
Your professor probably wants something like this:
def add(a, b):
new_dict = copy of a
for each key/value pair in b
if key in new_dict
add value to value already present in new_dict
else
insert key/value pair into new_dict
return new_dict
You can try this:
def add(dict1, dict2):
return dict([(key,dict1[key]+dict2[key]) for key in dict1.keys()])
I personally like using a dictionary's get method for this kind of merge:
def add(a, b):
result = {}
for dictionary in (a, b):
for key, value in dictionary.items():
result[key] = result.get(key, 0) + value
return result
I have the following dictionary (short version, real data is much larger):
dict = {'C-STD-B&M-SUM:-1': 0, 'C-STD-B&M-SUM:-10': 4.520475, 'H-NSW-BAC-ART:-9': 0.33784000000000003, 'H-NSW-BAC-ART:0': 0, 'H-NSW-BAC-ENG:-59': 0.020309999999999998, 'H-NSW-BAC-ENG:-6': 0,}
I want to divide it into smaller nested dictionaries, depending on a part of the key name.
Expected output would be:
# fixed closing brackets
dict1 = {'C-STD-B&M-SUM: {'-1': 0, '-10': 4.520475}}
dict2 = {'H-NSW-BAC-ART: {'-9': 0.33784000000000003, '0': 0}}
dict3 = {'H-NSW-BAC-ENG: {'-59': 0.020309999999999998, '-6': 0}}
Logic behind is:
dict1: if the part of the key name is 'C-STD-B&M-SUM', add to dict1.
dict2: if the part of the key name is 'H-NSW-BAC-ART', add to dict2.
dict3: if the part of the key name is 'H-NSW-BAC-ENG', add to dict3.
Partial code so far:
def divide_dictionaries(dict):
c_std_bem_sum = {}
for k, v in dict.items():
if k[0:13] == 'C-STD-B&M-SUM':
c_std_bem_sum = k[14:17], v
What I'm trying to do is to create the nested dictionaries that I need and then I'll create the dictionary and add the nested one to it, but I'm not sure if it's a good way to do it.
When I run the code above, the variable c_std_bem_sum becomes a tuple, with only two values that are changed at each iteration. How can I make it be a dictionary, so I can later create another dictionary, and use this one as the value for one of the keys?
One way to approach it would be to do something like
d = {'C-STD-B&M-SUM:-1': 0, 'C-STD-B&M-SUM:-10': 4.520475, 'H-NSW-BAC-ART:-9': 0.33784000000000003, 'H-NSW-BAC-ART:0': 0, 'H-NSW-BAC-ENG:-59': 0.020309999999999998, 'H-NSW-BAC-ENG:-6': 0,}
def divide_dictionaries(somedict):
out = {}
for k,v in somedict.items():
head, tail = k.split(":")
subdict = out.setdefault(head, {})
subdict[tail] = v
return out
which gives
>>> dnew = divide_dictionaries(d)
>>> import pprint
>>> pprint.pprint(dnew)
{'C-STD-B&M-SUM': {'-1': 0, '-10': 4.520475},
'H-NSW-BAC-ART': {'-9': 0.33784000000000003, '0': 0},
'H-NSW-BAC-ENG': {'-59': 0.020309999999999998, '-6': 0}}
A few notes:
(1) We're using nested dictionaries instead of creating separate named dictionaries, which aren't convenient.
(2) We used setdefault, which is a handy way to say "give me the value in the dictionary, but if there isn't one, add this to the dictionary and return it instead.". Saves an if.
(3) We can use .split(":") instead of hardcoding the width, which isn't very robust -- at least assuming that's the delimiter, anyway!
(4) It's a bad idea to use dict, the name of a builtin type, as a variable name.
That's because you're setting your dictionary and overriding it with a tuple:
>>> a = 1, 2
>>> print a
>>> (1,2)
Now for your example:
>>> def divide_dictionaries(dict):
>>> c_std_bem_sum = {}
>>> for k, v in dict.items():
>>> if k[0:13] == 'C-STD-B&M-SUM':
>>> new_key = k[14:17] # sure you don't want [14:], open ended?
>>> c_std_bem_sum[new_key] = v
Basically, this grabs the rest of the key (or 3 characters, as you have it, the [14:None] or [14:] would get the rest of the string) and then uses that as the new key for the dict.