Updating dictionaries without data loss - python

If I have two dictionaries that looks like this:
a = {"fruit":["orange", "lemon"], "vegetable":["carrot", "tomato"]}
b = {"fruit":["banana", "lime"]}
Is there a way I can update dictionary 'a' so that I don't overwrite the previous data, but simply append it so that my result would look like this?
a = {"fruit":["orange", "lemon", "banana", "lime"], "vegetable": ["carrot", "tomato"]}
I know there is something similar , but unfortunately it rewrites the values, which is not what I am looking to do:
a.update(b)
#returns a dictionary like the following {"fruit":["banana", "lime"], "vegetable":["carrot","tomato"]}, again, not what I want.

No way without a loop:
for k, v in b.items():
a[k].extend(v)
This assumes that a[k] actually exists . . . If you want to add it in the case where it is missing:
for k, v in b.items():
try:
a[k].extend(v)
except KeyError:
a[k] = v

You could use a defaultdict, but you have to iterate over the items.
from collections import defaultdict
a = defaultdict(list)
You could also define a helper method (but be careful not to call it with a normal dict, some type check may be appropriate):
def update(a,b):
for k, v in b.items():
a[k].extend(v)
The other option is to extend dict and override the update method to do it there.

You can also do a simple while loop:
accesos = {'carlos pinto': 23849284}
while True:
nueva_persona = input("Nombre?: ")
nueva_clave = input("Clave?: ")
accesos[nueva_persona] = nueva_clave
print(accesos)

Related

Splitting a dictionary by key suffixes

I have a dictionary like so
d = {"key_a":1, "anotherkey_a":2, "key_b":3, "anotherkey_b":4}
So the values and key names are not important here. The key (no pun intended) thing, is that related keys share the same suffix in my example above that is _a and _b.
These suffixes are not known before hand (they are not always _a and _b for example, and there are an unknown number of different suffixes.
What I would like to do, is to extract out related keys into their own dictionaries, and have all generated dictionaries in a list.
The output from above would be
output = [{"key_a":1, "anotherkey_a":2},{"key_b":3, "anotherkey_b":4}]
My current approach is to first get all the suffixes, and then generate the sub-dicts one at a time and append to the new list
output = list()
# Generate a set of suffixes
suffixes = set([k.split("_")[-1] for k in d.keys()])
# Create the subdict and append to output
for suffix in suffixes:
output.append({k:v for k,v in d.items() if k.endswith(suffix)})
This works (and is not prohibitively slow or anyhting) but I am simply wondering if there is a more elegant way to do it with a list or dict comprehension? Just out of interest...
Make your output a defaultdict rather than a list, with suffixes as keys:
from collections import defaultdict
output = defaultdict(lambda: {})
for k, v in d.items():
prefix, suffix = k.rsplit('_', 1)
output[suffix][k] = v
This will split your dict in a single pass and result in something like:
output = {"a" : {"key_a":1, "anotherkey_a":2}, "b": {"key_b":3, "anotherkey_b":4}}
and if you insist on converting it to a list, you can simply use:
output = list(output.values())
You could condense the lines
output = list()
for suffix in suffixes:
output.append({k:v for k,v in d.items() if k.endswith(suffix)})
to a list comprehension, like this
[{k:v for k,v in d.items() if k.endswith(suffix)} for suffix in suffixes]
Whether it is more elegant is probably in the eyes of the beholder.
The approach suggested by #Błotosmętek will probably be faster though, given a large dictionary, since it results in less looping.
def sub_dictionary_by_suffix(dictionary, suffix):
sub_dictionary = {k: v for k, v in dictionary.items() if k.endswith(suffix)}
return sub_dictionary
I hope it helps

Is there a shorthand for using the same variable being assigned for the argument in a function?

Is there a quicker way to write this:
def foo():
# What happens in here is irrelevant.
return new_value
dict['i_dont_want_to_type_this_twice'] = foo(dict['i_dont_want_to_type_this_twice'])
Like when you use x += 1
I don't think there's any built-in or standard library feature for this. The most idiomatic thing to do is probably define your own wrapper function, such as
def transform(d, k, f):
d[k] = f(d[k])
And then use it like so (note that I've renamed your dict to mydict to avoid masking the built-in):
transform(mydict, 'i_dont_want_to_type_this_twice', foo)
(I think apply() would make a decent name for this, but it's a built-in if you're using Python 2. Though it's been deprecated since 2.3, so there wouldn't be a lot of harm in it.)
You can do something like this, by using update on the dictionary.
d.update(a=foo(d.get('a', 0)))
Full demo:
d = {'a': 5}
def foo(val):
val += 100
return val
d.update(a=foo(d.get('a', 0)))
print(d) # outputs {'a': 105}
From the description of the dictionary update method:
D.update([E, ]**F) -> None. Update D from dict/iterable E and F.
If E is present and has a .keys() method, then does: for k in E: D[k] = E[k]
If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v
In either case, this is followed by: for k in F: D[k] = F[k]
So, if the key exists, it will update it, and if it does not, it will create it.
How about this for a one-liner assignment?
dict.update({key: foo(dict[key]) for key in ['i_dont_want_to_type_this_twice']})
Or, to update the entire dict:
dict = {k: foo(v) for k, v in dict.items()}

OrderedDictionary.popitem() unable to iterate over all values?

I try to iterate over an ordered dictionary in last in first out order.
While for a standard dictionary everything works fine, the first solution for the orderedDict reacts strange. It seems, that while popitem() returns one key/value pair (but somehow sequentially, since I can't replace kv_pair by two variables), iteration is finished then. I see no easy way to proceed to the next key/value pair.
While I found two working alternatives (shown below), both of them lack the elegance of the normal dictionary approach.
From what I found in the online help, it is impossible to decide, but I assume I have wrong expectations. Is there a more elgant approach?
from collections import OrderedDict
normaldict = {"0": "a0.csf", "1":"b1.csf", "2":"c2.csf"}
for k, v in normaldict.iteritems():
print k,":",v
d = OrderedDict()
d["0"] = "a0.csf"
d["1"] = "b1.csf"
d["2"] = "c2.csf"
print d, "****"
for kv_pair in d.popitem():
print kv_pair
print "++++"
for k in reversed(d.keys()):
print k, d[k]
print "%%%%"
while len(d) > 0:
k, v = d.popitem()
print k, v
dict.popitem() is not the same thing as dict.iteritems(); it removes one pair from the dictionary as a tuple, and you are looping over that pair.
The most efficient method is to use a while loop instead; no need to call len(), just test against the dictionary itself, an empty dictionary is considered false:
while d:
key, value = d.popitem()
print key, value
The alternative is to use reversed():
for key, item in reversed(d.items()):
print key, value
but that requires the whole dictionary to be copied into a list first.
However, if you were looking for a FIFO queue, use collections.deque() instead:
from collections import deque
d = deque(["a0.csf", "b1.csf", "c2.csf"])
while d:
item = d.pop()
or use deque.reverse().
d.popitems() will return only one tuple (k,v). So your for loop is iterating over the one item and the loop ends.
you can try
while d:
k, v = d.popitem()

Python Merge 2 Dictionaries without overwriting

If a and b are 2 dictionaries:
a = {'UK':'http://www.uk.com', 'COM':['http://www.uk.com','http://www.michaeljackson.com']}
bb = {'Australia': 'http://www.australia.com', 'COM':['http://www.Australia.com', 'http://www.rafaelnadal.com','http://www.rogerfederer.com']}
I want to merge them to get
{'Australia': ['http://www.australia.com'], 'COM': ['http://www.uk.com', 'http://www.michaeljackson.com', 'http://www.Australia.com', 'http://www.rafaelnadal.com', 'http://www.rogerfederer.com'], 'UK': ['http://www.uk.com']}
I want to union them i.e.
How to do it in Python without overwwriting and replacing any value?
Use a defaultdict:
from collections import defaultdict
d = defaultdict(list)
for dd in (a,bb):
for k,v in dd.items():
#Added this check to make extending work for cases where
#the value is a string.
v = (v,) if isinstance(v,basestring) else v #basestring is just str in py3k.
d[k].extend(v)
(but this is pretty much what I told you in my earlier answer)
This now works if your input dictionaries look like
{'Australia':['http://www.australia.com']}
or like:
{'Australia':'http://www.australia.com'}
However, I would advise against the latter form. In general, I think it's a good idea to keep all the keys/values of a dictionary looking the same (at least if you want to treat all the items the same as in this question). That means that if one value is a list, it's a good idea for all of them to be a list.
If you really insist on keeping things this way:
d = {}
for dd in (a,b):
for k,v in dd.items():
if(not isinstance(v,list)):
v = [v]
try:
d[k].extend(v)
except KeyError: #no key, no problem, just add it to the dict.
d[k] = v

modify a dictionary

I need to modify a dictionary. I have a dictionary with integer values and want to replace each value with the fraction of the total of all values, eg.:
census={a:4, b:1, c:3}; turnIntoFractions(census), should then print {a:0.5, b:0,125 ,c:0,375 }
I was thinking something like:
def turnIntoFractions:
L=d.keys()
total=sum(L)
F=[]
for count in L:
f.append(float(count/float(total))
return F
I'm kind of stuck, and it isn't working..
You can use dictionary comprehension.
def turnIntoFractions(d):
total = float(sum(d.values()))
return {key:(value/total) for key,value in d.items()}
Your first problem is that you are doing the sum of the keys, not the values:
total = sum(d.values())
Now, you can just modify the dictionary inline, instead of putting it into a new list:
for key in d.keys():
d[key] /= total # or d[key] = d[key] / total
My previous code goes through each key, retrieves the value, then divides by total, and then finally stores it back into d[key].
If you want a new dictionary returned, instead of just modifying the existing one, you can just start out with e = d.copy(), then use e instead.
You seem to want to edit the dict in place, but your code returns a new object, which is actually better practice.
def turnIntoFractions(mydict):
values=d.values()
total=float(sum(values))
result = {}
for key, val in mydict.items():
result[key] = val/total
return result
your code has the right idea, but also a few small mistakes.
here's a working code:
def turnIntoFractions(d):
L=d.values()
total=sum(L)
f=[]
for count in L:
f.append(float(count/float(total)))
return f
census={'a':4, 'b':1, 'c':3}
print(turnIntoFractions(census))
note that python is case sensitive so f is not the same as F, and also keys that are strings need to be quoted
Use dictionary comprehension
sum = float(sum(census.itervalues()))
newDict = {k : (v / sum) for k,v in census.iteritems()}
for python 2.6:
newDict = dict((k,v /sum) for (k,v) in census.iteritems())
The following Python code will modify the dictionary's keys to float values.
def turnIntoFractions(mydict):
total = sum(mydict.values())
for key in mydict:
mydict[key] = float(mydict[key]) / total

Categories