Adding more values on existing python dictionary key - python

I am new to python and i am stuck while making a dictionary.. please help :)
This is what I am starting with :
dict = {}
dict['a']={'ra':7, 'dec':8}
dict['b']={'ra':3, 'dec':5}
Everything perfect till now. I get :
In [93]: dict
Out[93]: {'a': {'dec':8 , 'ra': 7}, 'b': {'dec': 5, 'ra': 3}}
But now, if I want to add more things to key 'a' and i do :
dict['a']={'dist':12}
Then it erases the previous information of 'a' and what i get now is :
In [93]: dict
Out[93]: {'a': {'dist':12}, 'b': {'dec': 5, 'ra': 3}}
What i get want to have is :
In [93]: dict
Out[93]: {'a': {'dec':8 , 'ra': 7, 'dist':12}, 'b': {'dec': 5, 'ra': 3}}
Can someone please help??

>>> d = {}
>>> d['a'] = {'ra':7, 'dec':8}
>>> d['b'] = {'ra':3, 'dec':5}
>>> d['a']['dist'] = 12
>>> d
{'a': {'dec': 8, 'dist': 12, 'ra': 7}, 'b': {'dec': 5, 'ra': 3}}
If you want to update dictionary from another dictionary, use update():
Update the dictionary with the key/value pairs from other, overwriting
existing keys.
>>> d = {}
>>> d['a'] = {'ra':7, 'dec':8}
>>> d['b'] = {'ra':3, 'dec':5}
>>> d['a'].update({'dist': 12})
>>> d
{'a': {'dec': 8, 'dist': 12, 'ra': 7}, 'b': {'dec': 5, 'ra': 3}}
Also, don't use dict as a variable name - it shadows built-in dict type. See what can possibly happen:
>>> dict(one=1)
{'one': 1}
>>> dict = {}
>>> dict(one=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'dict' object is not callable

Do this:
dict['a']['dist'] = 12

Try this:
dict['a'].update( {'dist': 12} )

Instead of assigning {'dist':12} to dict['a'], use the update method.
dict['a'].update( {'dist':12} )
This has the advantage of not needing to "break apart" the new dictionary to find which key(s) to insert into the target. Consider:
a = build_some_dictionary()
for k in a:
dict['a'] = a[k]
vs.
dict['a'].update(a)

Related

Python - type conversion loop through dictionary

I have a dictionary filled with number strings and i want to convert every of those values into binary. Here is what i tried:
for k,v in ValueDict.items():
ValueDict.update(k:bin(v))
However this does not work. PyCharm says "Illegal target for variable annotation", i dont understand what this means. As far as i know, variable annotation is a way of "commenting" on the types of a variable, but i dont understand how this is related to my issue...
Thanks in advance!
Try using dictionary comprehension:
print({k:bin(v) for k,v in ValueDict.items()})
Or if version less then 2.5:
print(dict((k:bin(v) for k,v in ValueDict.items())))
Your code doesn't work from : in ValueDict.update(k:bin(v))
To use your style:
for k,v in ValueDict.items():
ValueDict.update({k:bin(v)})
Or:
for k,v in ValueDict.items():
ValueDict[k]=bin(v)
You need to provide a dict to update method.
for k,v in ValueDict.items():
ValueDict.update({k:bin(v)})
See the documentation at dict.update:
Update the dictionary with the key/value pairs from other, overwriting existing keys. Return None.
update() accepts either another dictionary object or an iterable of key/value pairs (as tuples or other iterables of length two). If keyword arguments are specified, the dictionary is then updated with those key/value pairs: d.update(red=1, blue=2).
Examples:
# dict expression
d = {"a":1, "b":2, "c":3}
>>> {'a': 1, 'c': 3, 'b': 2}
# multiple updates: no loop needed
d.update( {"a" : 11, "b" : 22} )
>>> {'a': 11, 'c': 3, 'b': 22}
# multiple adds: no loop needed (also no '' around keys)
d.update( A = 111, B = 22 )
>>> {'a': 11, 'A': 111, 'c': 3, 'b': 22, 'B': 22}
# updating all keys using loop
for k,v in d.items():
d[k]=v*2
>>> {'a': 22, 'A': 222, 'c': 6, 'b': 44, 'B': 44}
# add values to a list if same keys and not yet in
# providing an existing key here would overwrite that one
new_ones = ( ("X",42), ("X",4711) )
for k,v in new_ones:
entry = d.setdefault(k,[])
entry.append(v)
>>> {'a': 22, 'A': 222, 'c': 6, 'b': 44, 'B': 44, 'X': [42, 4711]}
# no loop - update from iterable of key/value pairs
new_ones = ( ("i",42), ("j",4711) )
d.update(new_ones)
>>> {'a': 22, 'A': 222, 'c': 6, 'b': 44, 'i': 42, 'j': 4711, 'B': 44, 'X': [42, 4711]}

Why do changes to a nested dict inside dict2 affect dict1? [duplicate]

This question already has answers here:
assigning value in python dict (copy vs reference)
(2 answers)
Closed 4 years ago.
I don't understand these cases:
content = {'a': {'v': 1}, 'b': {'v': 2}}
d1 = {'k1': {}}
d2 = {'k2': {}}
d1['k1'].update(content)
print(d1)
content['a']['v'] = 3
content['b']['v'] = 4
d2['k2'].update(content)
print(d2)
print(d1)
>>> {'k1': {'a': {'v': 1}, 'b': {'v': 2}}}
>>> {'k2': {'a': {'v': 3}, 'b': {'v': 4}}}
>>> {'k1': {'a': {'v': 3}, 'b': {'v': 4}}}
In the case above the content of d1 is changed after the variable content is updated.
content = {'a': 1, 'b': 2}
d1 = {'k1': {}}
d2 = {'k2': {}}
d1['k1'].update(content)
print(d1)
content['a'] = 3
content['b'] = 4
d2['k2'].update(content)
print(d2)
print(d1)
>>> {'k1': {'a': 1, 'b': 2}}
>>> {'k2': {'a': 3, 'b': 4}}
>>> {'k1': {'a': 1, 'b': 2}}
However in this case d1 is not altered even if the variable content was changed. I don't understand why... any idea?
see shallow vs deep copy.
The copy here is a shallow copy so the first level entries are copies but the nested structures are references.
A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects
found in the original.
A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the
original.
The key difference between your two snippets is that content['a']['v'] = 3 is a completely different operation than content['a'] = 3. In the first case, you're modifying the inner dictionary by changing its v key. In the latter case, you're replacing the value in the dictionary without modifying it.
It's confusing when everything's a dictionary, so let's replace the dictionaries with variables and instances of a class:
class Person:
def __init__(self, name):
self.name = name
# these two variables are represent your `content` dict
a = Person('Andy') # this variable represents `{'v': 1}`
b = Person('Belle') # this variable represents `{'v': 2}`
# the equivalent of `d1['k1'].update(content)` is a simple assignment
k1_a = a
# and the equivalent of `content['a']['v'] = 3` is changing a's name
a.name = 'Aaron'
# because k1_a and a are the same Person instance, this is reflected in k1_a:
print(k1_a.name) # output: Aaron
The key points to note here are that
k1_a = a doesn't make a copy of the Person; similar to how d1['k1'].update(content) doesn't make a copy of the {'v': 1} dict.
a.name = 'Aaron' modifies the Person; similar to how content['a']['v'] = 3 modifies the inner dict.
The equivalent of your 2nd snippet looks like this:
a = 'Andy'
b = 'Belle'
k1_a = a
a = 'Aaron'
print(k1_a) # output: Andy
This time, no object is ever modified. All we're doing is overwriting the value of the a variable, exactly how content['a'] = 3 overwrites the value of the a key in your dict.
If you don't want the changes in the inner dicts to be reflected in other dicts, you have to copy them with copy.deepcopy:
import copy
content = {'a': {'v': 1}, 'b': {'v': 2}}
d1 = {'k1': {}}
d2 = {'k2': {}}
d1['k1'].update(copy.deepcopy(content))
print(d1)
content['a']['v'] = 3
content['b']['v'] = 4
d2['k2'].update(copy.deepcopy(content))
print(d2)
print(d1)
# output:
# {'k1': {'a': {'v': 1}, 'b': {'v': 2}}}
# {'k2': {'a': {'v': 3}, 'b': {'v': 4}}}
# {'k1': {'a': {'v': 1}, 'b': {'v': 2}}}
If we replace the update() with a simple assignment:
# d1['k1'].update(content)
d1['k1'] = content
We get:
{'k1': {'a': 1, 'b': 2}}
{'k2': {'a': 3, 'b': 4}}
{'k1': {'a': 3, 'b': 4}}
(Which is different from what update does in your example.) This is because update accepts an iterable (e.g. a dictionary) and copies the key value pairs inside. It's equivalent to doing:
d1['k1'] = {k: v for k, v in content.items()}
And of course, the int values are immutables and so their reassignment does not affect the original.

Convert class with references to other classes to dict in python

My goal is to convert a class to a dict, recursively. I understand that I need to specify the rules related to the conversion, but I feel like there is some way for built-in python to recurse the class and produce a dict. See the following code:
class Foo:
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def __iter__(self):
yield 'a', self.a
yield 'b', self.b
yield 'c', self.c
class Bar:
def __init__(self, foos):
self.foos = foos
self.d = 5
def __iter__(self):
yield 'foos', self.foos
yield 'd', self.d
foos = [Foo(), Foo(), Foo()]
bar = Bar(foos)
print(dict(bar))
The result of this is:
{'foos': [<__main__.Foo object at 0x108e6be48>, <__main__.Foo object at 0x108e6bef0>, <__main__.Foo object at 0x108e6bf28>], 'd': 5}
foos in this case is a list of Foo()s, which I would hope to see an expanded list of dicts. I know I can add the following to the Foo class to make this work:
def __repr__(self):
return repr(dict(self))
Results in the desired output:
{'foos': [{'a': 1, 'b': 2, 'c': 3}, {'a': 1, 'b': 2, 'c': 3}, {'a': 1, 'b': 2, 'c': 3}], 'd': 5}
but that approach seems hacky - as in, I'm forcing it to represent itself as a dict, rather than naturally iterable (which feels like I'm trying to put a square peg in a round hole).
My question to the python world is: what is the proper way to approach this so that I can call dict() on my class and get a full dictionary?
I've searched around and can't seem to find anything specific to this topic so I'm going to ask here. If this already exists please point me in the right direction. Thanks in advance for your help!
I've came up with two hacks that can fill your needs.
1st: Exposing dicts in foos variable by replacing this line:
foos = [Foo(), Foo(), Foo()]
by this kind of hacks using list comprehension:
foos =[dict(k) for k in [Foo(), Foo(), Foo()]]
Or, simply like this:
foos = [dict(Foo()), dict(Foo()), dict(Foo())]
then:
print(dict(bar))
>>> {'d': 5, 'foos': [{'a': 1, 'c': 3, 'b': 2}, {'a': 1, 'c': 3, 'b': 2}, {'a': 1, 'c': 3, 'b': 2}]}
2nd: Exposing dicts inside Bar.__iter__() by replacing this line:
yield 'foos', self.foos
by:
yield [dict(k) for k in self.foos]
Then:
print(dict(bar))
>>> {'d': 5, 'foos': [{'a': 1, 'c': 3, 'b': 2}, {'a': 1, 'c': 3, 'b': 2}, {'a': 1, 'c': 3, 'b': 2}]}
Bonus (not exactly what you want): Using dict comprehension by replacing this line:
print(dict(bar))
by:
print({k:v if isinstance(v, int) else [dict(j) for j in v] for k,v in dict(bar).items()})
which will print:
>>> {'d': 5, 'foos': [{'a': 1, 'c': 3, 'b': 2}, {'a': 1, 'c': 3, 'b': 2}, {'a': 1, 'c': 3, 'b': 2}]}

Pythonic way of finding duplicate maps in a list while ignoring certain keys, and combining the duplicate maps to make a new list

I want to write a code which takes the following inputs:
list (list of maps)
request_keys (list of strings)
operation (add,substract,multiply,concat)
The code would look at the list for the maps having the same value for all keys except the keys given in request_keys. Upon finding two maps for which the value in the search keys match, the code would do the operation (add,multiple,substract,concat) on the two maps and combine them into one map. This combination map would basically replace the other two maps.
i have written the following peice of code to do this. The code only does add operation. It can be extended to make the other operations
In [83]: list
Out[83]:
[{'a': 2, 'b': 3, 'c': 10},
{'a': 2, 'b': 3, 'c': 3},
{'a': 2, 'b': 4, 'c': 4},
{'a': 2, 'b': 3, 'c': 2},
{'a': 2, 'b': 3, 'c': 3}]
In [84]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:def func(list,request_keys):
: new_list = []
: found_indexes = []
: for i in range(0,len(list)):
: new_item = list[i]
: if i in found_indexes:
: continue
: for j in range(0,len(list)):
: if i != j and {k: v for k,v in list[i].iteritems() if k not in request_keys} == {k: v for k,v in list[j].iteritems() if k not in request_keys}:
: found_indexes.append(j)
: for request_key in request_keys:
: new_item[request_key] += list[j][request_key]
: new_list.append(new_item)
: return new_list
:--
In [85]: func(list,['c'])
Out[85]: [{'a': 2, 'b': 3, 'c': 18}, {'a': 2, 'b': 4, 'c': 4}]
In [86]:
What i want to know is, is there a faster, more memory efficient, cleaner and a more pythonic way of doing the same?
Thank you
You manually generate all the combinations and then compare each of those combinations. This is pretty wasteful. Instead, I suggest grouping the dictionaries in another dictionary by their matching keys, then adding the "same" dictionaries. Also, you forgot the operator parameter.
import collections, operator, functools
def func(lst, request_keys, op=operator.add):
matching_dicts = collections.defaultdict(list)
for d in lst:
key = tuple(sorted(((k, d[k]) for k in d if k not in request_keys)))
matching_dicts[key].append(d)
for group in matching_dicts.values():
merged = dict(group[0])
merged.update({key: functools.reduce(op, (g[key] for g in group))
for key in request_keys})
yield merged
What this does: First, it creates a dictionary, mapping the key-value pairs that have to be equal for two dictionaries to match to all those dictionaries that have those key-value pairs. Then it iterates the dicts from those groups, using one of that group as a prototype and updating it with the sum (or product, or whatever, depending on the operator) of the all the dicts in that group for the required_keys.
Note that this returns a generator. If you want a list, just call it like list(func(...)), or accumulate the merged dicts in a list and return that list.
from itertools import groupby
from operator import itemgetter
def mergeDic(inputData, request_keys):
keys = inputData[0].keys()
comparedKeys = [item for item in keys if item not in request_keys]
grouper = itemgetter(*comparedKeys)
result = []
for key, grp in groupby(sorted(inputData, key = grouper), grouper):
temp_dict = dict(zip(comparedKeys, key))
for request_key in request_keys:
temp_dict[request_key] = sum(item[request_key] for item in grp)
result.append(temp_dict)
return result
inputData = [{'a': 2, 'b': 3, 'c': 10},
{'a': 2, 'b': 3, 'c': 3},
{'a': 2, 'b': 4, 'c': 4},
{'a': 2, 'b': 3, 'c': 2},
{'a': 2, 'b': 3, 'c': 3}]
from pprint import pprint
pprint(mergeDic(inputData,['c']))

Python adding dictionary values with same key within a list

i just picked up python not too long ago.
An example below
i have a dictionary within a list
myword = [{'a': 2},{'b':3},{'c':4},{'a':1}]
I need to change it to the output below
[{'a':3} , {'b':3} , {'c':4}]
is there a way where i can add the value together? I tried using counter, but it prints out the each dict out.
what i did using Counter:
for i in range(1,4,1):
text = myword[i]
Print Counter(text)
The output
Counter({'a': 2})
Counter({'b': 3})
Counter({'c': 4})
Counter({'a': 1})
i have read the link below but what they compared was between 2 dict.
Is there a better way to compare dictionary values
Thanks!
Merge dictionaries into one dictionary (Counter), and split them.
>>> from collections import Counter
>>> myword = [{'a': 2}, {'b':3}, {'c':4}, {'a':1}]
>>> c = Counter()
>>> for d in myword:
... c.update(d)
...
>>> [{key: value} for key, value in c.items()]
[{'a': 3}, {'c': 4}, {'b': 3}]
>>> [{key: value} for key, value in sorted(c.items())]
[{'a': 3}, {'b': 3}, {'c': 4}]

Categories