Dictionary of dictionaries in Python? - python

From another function, I have tuples like this ('falseName', 'realName', positionOfMistake), eg. ('Milter', 'Miller', 4).
I need to write a function that make a dictionary like this:
D={realName:{falseName:[positionOfMistake], falseName:[positionOfMistake]...},
realName:{falseName:[positionOfMistake]...}...}
The function has to take a dictionary and a tuple like above, as arguments.
I was thinking something like this for a start:
def addToNameDictionary(d, tup):
dictionary={}
tup=previousFunction(string)
for element in tup:
if not dictionary.has_key(element[1]):
dictionary.append(element[1])
elif:
if ...
But it is not working and I am kind of stucked here.

If it is only to add a new tuple and you are sure that there are no collisions in the inner dictionary, you can do this:
def addNameToDictionary(d, tup):
if tup[0] not in d:
d[tup[0]] = {}
d[tup[0]][tup[1]] = [tup[2]]

Using collections.defaultdict is a big time-saver when you're building dicts and don't know beforehand which keys you're going to have.
Here it's used twice: for the resulting dict, and for each of the values in the dict.
import collections
def aggregate_names(errors):
result = collections.defaultdict(lambda: collections.defaultdict(list))
for real_name, false_name, location in errors:
result[real_name][false_name].append(location)
return result
Combining this with your code:
dictionary = aggregate_names(previousFunction(string))
Or to test:
EXAMPLES = [
('Fred', 'Frad', 123),
('Jim', 'Jam', 100),
('Fred', 'Frod', 200),
('Fred', 'Frad', 300)]
print aggregate_names(EXAMPLES)

dictionary's setdefault is a good way to update an existing dict entry if it's there, or create a new one if it's not all in one go:
Looping style:
# This is our sample data
data = [("Milter", "Miller", 4), ("Milter", "Miler", 4), ("Milter", "Malter", 2)]
# dictionary we want for the result
dictionary = {}
# loop that makes it work
for realName, falseName, position in data:
dictionary.setdefault(realName, {})[falseName] = position
dictionary now equals:
{'Milter': {'Malter': 2, 'Miler': 4, 'Miller': 4}}

Related

How to store key value pairs

I want to store key-value pairs, but I don't know how to do it.
What I want to achieve is a variable that would store the different value pairs.
What I would want is something like this:
dic = {}
valuepair = (2,3), "cell1"
Each value pair is unique and I would want to be able to do something like this:
dic[(2,3)] = "cell1"
dic["cell1"] = (2,3)
Is there a way to achieve something like that for many different unique value pairs?
If you ask if you can use a tuple as a key - yes, for example:
dic[(2,3)] = "cell1"
print(dic[(2,3)])
would show cell1
or create an inverse dict like this:
inverse_d = {v:k for key, value in d}
Key-Value pair means a key mapped to a value. And what you are doing is right, but if you got the key, you can get value from it. So you need not store value ("cell1"), again as a key, when it is already a value. Sorry, if I don't get your question. Or you can do this too:
x = [("k1","v1"),("k2,"v2")]
d = dict(x)
print(d)
OUTPUT : {"k1":"v1", "k2":"v2"}
You can always do that, but why would you need that is still a question.
valuepairs = [[(2,3), "cell1"], [(4,5), "cell2"]]
dic = {}
for x, y in valuepairs:
dic[x] = y
dic[y] = x
print(dic)
# {(2, 3): 'cell1', 'cell1': (2, 3), (4, 5): 'cell2', 'cell2': (4, 5)}

Merging values from 2 dictionaries (Python)

(I'm new to Python!)
Trying to figure out this homework question:
The function will takes a​s input​ two dictionaries, each mapping strings to integers. The function will r​eturn​ 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

Adding Multiple Values to Single Key in Python Dictionary Comprehension

I wanted to learn how to use dictionary comprehension and decided to use one for the previously solved task. I need to assign multiple values to the same key. I was wondering if there's a better way to achieve what I'm trying to do than with the code I've written so far.
graph = {(x1,y1): [(c,d) for a,b,c,d in data if a == x1 and b == y1] for x1 ,y1, x2, y2 in data}
For example I have this:
data = {(1,2,1,5),(1,2,7,2),(1,5,4,7),(4,7,7,5)}
The first two values should create a key and the remaining two should be added as a value of a key.
With the given example I would like to return:
{(1, 2): [(1, 5), (7, 2)], (1, 5): [(4, 7)], (4, 7): [(7, 5)]}
Is there an easier way to do it than iterate through the entire data just to find the matching values?
Using this dict comprehension isn’t an efficient way here. It loops over the same input data repeatedly.
It's more Pythonic to just use a simple for loop, iterating the data only once:
from collections import defaultdict
data = {(1,2,1,5),(1,2,7,2),(1,5,4,7),(4,7,7,5)}
output = defaultdict(list)
for a, b, c, d in data:
output[a, b].append((c, d))
Your code is neat but the time complexity is O(n^2), which can be reduced to O(n).
data = {(1,2,1,5),(1,2,7,2),(1,5,4,7),(4,7,7,5)}
result = dict()
for item in data:
key = (item[0],item[1])
value = result.setdefault(key,[])
value.append((item[2],item[3]))
result[key] = value
print result
In my opinion, using a for loop can make codes more comprehensive
I don't know if it is the best answer but I would do something like that :
m_dict = {}
for val in data:
key = (val[0],val[1])
if key in m_dict:
m_dict[key].append((val[2],val[3]))
else:
m_dict[key] = [(val[2],val[3])]
Or more concisely using setdefault:
m_dict = {}
for val in data:
key = (val[0],val[1])
obj = m_dict.setdefault(key,[])
obj.append((val[2],val[3]))
In this instance, I would use itertools.groupby. For your example:
dict(groupby(data, lambda t: (t[0], t[1])))
This will produce a dict with the keys equal to (1, 2), (1, 5), and (4, 7) and the values consisting of (1, 2, 1, 5), (1, 2, 7, 2)... which should be sufficient for most uses. You can also post-process the grouped list, if need be.
As noted in the comments below, groupby requires sorted data. As such, you will need to sort before grouping and will probably want to cast the iterator to a list:
first_two = lambda tup: (tup[0], tup[1])
groups = groupby(sorted(data, key=first_two), first_two)
target = {k: list(g) for k, g in groups}

Modifying tuple element from the dictionary

I have a following dictionary as input:
my_dict[(1, 2)] = (3,4)
Now what I want to have convert it to is:
my_dict[(1,2)] = (3,40)
What is the best and efficient way to do this?
The dictionary itself is not very big...
I could probably do something like:
for (var1,var2),(var3,var) in my_dict.iteritems():
del my_dict[(var1,var2)]
my_dict[(var1,var2)] = (var3, var5)
but I don't think its right approach as I modify the dictionary in a loop.
You can just assign directly to the key; no need to delete the key first.
You could loop over the dictionary, yielding keys (your tuples); no need to unpack these even:
for key in my_dict:
my_dict[key] = (my_dict[key][0], var5)
or include the values:
for key, (val1, _) in my_dict.iteritems():
my_dict[key] = (val1, var5)
This unpacks just the value so you can reuse the first element. I've used _ as the name for the second value element to document it'll be ignored in the loop.
my_dict={}
my_dict[(1, 2)] = (3,4)
for i,val in my_dict.items():
my_dict[i]=(3,24)
print my_dict
#output {(1, 2): (3, 24)}
other way.
for i in my_dict.keys():
my_dict[i]=(3,24)
print my_dict
also
for i in my_dict:
my_dict[i]=(3,24)
print my_dict
You could do something like this:
my_dict[(1, 2)] = (3,4)
my_Dict2={i:(j[0],j[1]*10) for i,j in my_Dict.items()}
But I'm not sure if this is what your looking for since 'var5' in your code snippet is not defined. However, if you need to modify a tuple, there is probably a better type to use.

retrieving keys from dictionaries depending on value in python

I'm trying to find the most efficient way in python to create a dictionary of 'guids' (point ids in rhino) and retrieve them depending on the value(s) I assign them, change that value(s) and restoring them back in the dictionary. One catch is that with Rhinoceros3d program the points have a random generated ID number which I don't know so I can only call them depending on the value I give them.
are dictionaries the correct way? should the guids be the value instead of the keys?
a very basic example :
arrPts=[]
arrPts = rs.GetPoints() # ---> creates a list of point-ids
ptsDict = {}
for ind, pt in enumerate(arrPts):
ptsDict[pt] = ('A'+str(ind))
for i in ptsDict.values():
if '1' in i :
print ptsDict.keys()
how can I make the above code print the key that has the value '1' , instead of all the keys? and then change the key's value from 1 to e.g. 2 ?
any help also on the general question would be appreciated to know I'm in the right direction.
Thanks
Pav
You can use dict.items().
An example:
In [1]: dic={'a':1,'b':5,'c':1,'d':3,'e':1}
In [2]: for x,y in dic.items():
...: if y==1:
...: print x
...: dic[x]=2
...:
a
c
e
In [3]: dic
Out[3]: {'a': 2, 'b': 5, 'c': 2, 'd': 3, 'e': 2}
dict.items() returns a list of tuples containing keys and value pairs in python 2.x:
In [4]: dic.items()
Out[4]: [('a', 2), ('c', 2), ('b', 5), ('e', 2), ('d', 3)]
and in python 3.x it returns an iterable view instead of list.
I think you want the GUID's to be values, not keys, since it looks like you want to look them up by something you assign. ...but it really depends on your use case.
# list of GUID's / Rhinoceros3d point ids
arrPts = ['D20EA4E1-3957-11d2-A40B-0C5020524153',
'1D2680C9-0E2A-469d-B787-065558BC7D43',
'ED7BA470-8E54-465E-825C-99712043E01C']
# reference each of these by a unique key
ptsDict = dict((i, value) for i, value in enumerate(arrPts))
# now `ptsDict` looks like: {0:'D20EA4E1-3957-11d2-A40B-0C5020524153', ...}
print(ptsDict[1]) # easy to "find" the one you want to print
# basically make both keys: `2`, and `1` point to the same guid
# Note: we've just "lost" the previous guid that the `2` key was pointing to
ptsDict[2] = ptsDict[1]
Edit:
If you were to use a tuple as the key to your dict, it would look something like:
ptsDict = {(loc, dist, attr3, attr4): 'D20EA4E1-3957-11d2-A40B-0C5020524153',
(loc2, dist2, attr3, attr4): '1D2680C9-0E2A-469d-B787-065558BC7D43',
...
}
As you know, tuples are immutable, so you can't change the key to your dict, but you can remove one key and insert another:
oldval = ptsDict.pop((loc2, dist2, attr3, attr4)) # remove old key and get value
ptsDict[(locx, disty, attr3, attr4)] = oldval # insert it back in with a new key
In order to have one key point to multiple values, you'd have to use a list or set to contain the guids:
{(loc, dist, attr3, attr4): ['D20E...', '1D2680...']}

Categories

Resources