i have a dic in this form:
dic = {'movie1':{('bob',1),('jim',3),('dianne',4)},
'movie2': {('dianne',1),('bob',3),('asz',4)}}
it consists of of movie_name as keys, and tuples of values with (name,score) for each moviee
i want to convert this into:
{ 'bob': { 'movie1': 1,'movie2': 3},
'jim': {'movie1': 3},
'dianne': {'movie1': 4,'movie2': 1},
'asz': {'movie2: 4} }
i.e movie reviewed by each person, and the score for each movie.
Im lookingo for a function in which i can pass my dictionary 'dic' and it gives this result
What i tried was:
def reviewer_rank(db):
main_l=[]
for i in dic.values():
temp_l = list(i)
temp_l=dict(temp_l).keys()
main_l.extend(temp_l)
return main_l
i was able to get all the names of the dict in the list
You could use a defaultdict to avoid some bumpy code checking for the existence of each name in the result dict:
from collections import defaultdict
d = defaultdict(dict)
for movie, scores in dic.items():
for name, score in scores:
d[name][movie] = score
d
# defaultdict: {'bob': {'movie1': 1, 'movie2': 3}, 'asz': {'movie2': 4}, 'jim': {'movie1': 3}, 'dianne': {'movie1': 4, 'movie2': 1}}
You can iterate over the key-value tuples k,vs of the outer dictionary, and then for every tuple u, s in the value vs, you assign result[u][k] with s.
Since it is not certain that u is already in the result dictionary, we better use a defaultdict:
from collections import defaultdict
result = defaultdict(dict)
for k, vs in dic.items():
for u, s in vs:
result[u][k] = s
You can later cast the result back to a dict, with:
dict(result)
Note however that a defaultdict is a subclass of dict, so all dictionary operations are supported.
Here is a naive solution. It is just a simple case of looping over your input dict restructuring it into a new one with the required structure:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from collections import defaultdict
dic = {'movie1': {('bob', 1), ('jim', 3), ('dianne', 4)},
'movie2': {('dianne', 1), ('bob', 3), ('asz', 4)}}
raters = defaultdict(dict)
for movie, ratings in dic.items():
for rater, rating in ratings:
raters[rater][movie] = rating
Hope this helps!
You can organize your current data structure into tuples, and create a new dict of dict based on that. Do that with a generator, and it will yield one item at a time.
Using namedtuple you can access your data using strings instead of ints, which is more readable.
from collections import defaultdict, namedtuple
entries = namedtuple('Entries', 'name movie score')
new_dic = defaultdict(dict)
keys = (entries(name[0], k, name[1]) for k, v in dic.items() for name in v)
for item in keys:
new_dic[item.name][item.movie] = item.score
Related
I have the following dictionary:
data = {112: [25083], 25091: [6939], 32261: [9299, 6939, 3462], 32934: [7713, 6762, 6939], 34854: [6939], 56630: [7713]}
I am trying to overcome with the most frequent values. The output has to look like ({value: number, ...}):
{6939:4, 7713:2, 25083:1, 9299:1, 3462:1, 6762:1}
or ({value: keys, ...})
{6939:[25091, 32261, 32934, 34854], 7713:[32934, 56630], 25083:[25083], 9299:[32261], 3462:[32261], 6762:32934 }
I use the script for the normal dictionary, but for unhashed I don't know how to manage it.
k = {}
from collections import defaultdict
for key, val in data.items():
for i in val:
k.setdefault(i, set()).add(k)
You can use Counter and defaultdict:
from collections import Counter, defaultdict
from itertools import chain
data = {112: [25083], 25091: [6939], 32261: [9299, 6939, 3462], 32934: [7713, 6762, 6939], 34854: [6939], 56630: [7713]}
counter = Counter(chain.from_iterable(data.values()))
print(counter) # Counter({6939: 4, 7713: 2, 25083: 1, 9299: 1, 3462: 1, 6762: 1})
data_inverted = defaultdict(list)
for k, vs in data.items():
for v in vs:
data_inverted[v].append(k)
print(data_inverted)
# defaultdict(<class 'list'>,
# {25083: [112],
# 6939: [25091, 32261, 32934, 34854],
# 9299: [32261],
# 3462: [32261],
# 7713: [32934, 56630],
# 6762: [32934]})
Actually, if you are going to get data_inverted anyway, you can use the following after data_inverted (instead of using collections.Counter:
counter = {k: len(v) for k, v in data_inverted.items()}
In python 3.8, I have the following dict:
dict_base= dict()
Then I am generating another dict in my operation
dict_1={'Sedan': 'Accord',
'SUV': 'Pilot'
}
dict_base.append(dict1)
This appends dict1 to dict_base.
Next I have a second dict
dict_2={'Sedan': 'Camry',
'SUV': 'Highlander'
}
dict_base.append(dict_2)
What I am expecting is to see a result as follows:
dict_base={'Sedan': ['Accord', 'Camry'],
'SUV': ['Pilot', 'Highlander']
}
What I am seeing is
dict_base={'Sedan':'Camry',
'SUV':'Highlander'
}
So, I am not sure how to append correctly...as it appears my append operation is overwriting the previous values.
Thanks!
This is likely a good usecase for collections.defaultdict. You can't magically append each value of one dict containing strings to the corresponding keys of a dict containing lists. Python has no idea what you want to do, so you have to spell it out.
Make a dictionary that defaults to lists for missing elements:
dict_base = collections.defaultdict(list)
For each element of dict_1, dict_2, etc, tell python what to do with the values:
for k, v in dict_1.items():
dict_base[k].append(v)
Do the same thing for dict_2, or better yet, write a function:
def append_base(base, d):
for k, v in d.items():
base[k].append(v)
You can also do this with conventional dictionaries, especially if you know the list of keys ahead of time:
keys = ['Sedan', 'SUV']
dict_base = {k: [] for k in keys}
dict_1 = {'Sedan': 'Accord', 'SUV': 'Pilot'}
dict_2 = {'Sedan': 'Camry', 'SUV': 'Highlander'}
You can use itertools with collections:
import itertools
import collections
result = collections.defaultdict(list)
for key, value in itertools.chain(dict_1.items(), dict_2.items()):
result[key].append(value)
print(dict(result))
# Outputs {'Sedan': ['Accord', 'Camry'], 'SUV': ['Pilot', 'Highlander']}
You can use collections:
import collections
result = collections.defaultdict(list)
for d in (dict_1, dict_2):
for key, value in d.items():
result[key].append(value)
print(dict(result))
# Outputs {'Sedan': ['Accord', 'Camry'], 'SUV': ['Pilot', 'Highlander']}
Hell, you can even use nothing:
result = {}
for d in (dict_1, dict_2):
for key, value in d.items():
result.setdefault(key, []).append(value)
print(result)
# Outputs {'Sedan': ['Accord', 'Camry'], 'SUV': ['Pilot', 'Highlander']}
Instead of defining dict_base as dict, you can use collections.defaultdict
It can be this way -
from collections import defaultdict
dict_1={'Sedan': 'Accord',
'SUV': 'Pilot'
}
dict_2={'Sedan': 'Camry',
'SUV': 'Highlander'
}
dict_base = defaultdict(list)
for d in (dict_1, dict_2):
for key, value in d.items():
dict_base[key].append(value)
I am trying to create a nested dictionary. I have a list of tuples (called 'kinetic_parameters') which looks like this:
('New Model','v7','k1',0.1)
('New Model','v8','k2',0.2)
('New Model','v8','k3',0.3)
I need the second column to be the outer key and the value to be another dictionary with inner key being the third column and value being the number in the fourth.
I currently have:
for i in kinetic_parameters:
dict[i[1]]={}
dict[i[1]][i[2]]=i[3]
But this code will not deal with multiple keys in the inner dictionary so I lose some information. Does anybody know how to correct my problem?
I'm using Python 2.7 and I want the output to look like this:
{'v7': {'k1': 0.1}, 'v8':{'k2':0.2, 'k3': 0.3}}
Use a defaultdict, and don't use dict as a variable name, since we need it to refer to the dictionary type:
import collections
d = collections.defaultdict(dict)
for i in kinetic_parameters:
d[i[1]][i[2]]=i[3]
This will create the dictionaries automatically.
Right, if the major ("outer") key has been seen before you should be using the existing dictionary. Or put the other way around: Create an embedded dictionary only if does not exist, then add the value. Here's the logic, using tuple assignment for clarity:
nested = dict()
for row in kinetic_parameters:
_model, outkey, inkey, val = row
if outkey not in d:
nested[outkey] = dict()
nested[outkey][inkey] = val
Or you can skip the existence check by using defaultdict, which can create new embedded dicts as needed:
from collections import defaultdict
nested = defaultdict(dict)
for row in kinetic_parameters:
_model, outkey, inkey, val = row
nested[outkey][inkey] = val
In your code on every loop dictionary is re-initialized. You need to initialize the dictionary first and then add items to it
for i in kinetic_parameters:
d[i[1]]={}
for i in kinetic_parameters:
d[i[1]][i[2]]=i[3]
or check it before initializing
for i in kinetic_parameters:
if d.get(i[1]) is None:
d[i[1]]={}
d[i[1]][i[2]]=i[3]
kinetic_parameters = [('New Model','v7','k1',0.1),
('New Model','v8','k2',0.2),
('New Model','v8','k3',0.3)
]
d = {}
for i in kinetic_parameters:
if i[1] not in d.keys(): # Check if v7, v8 etc is present.
d[i[1]] = {} # Create an empty dict if absent
d[i[1]][i[2]] = i[3]
print(d)
Output is what you expected:
{'v7': {'k1': 0.1}, 'v8': {'k3': 0.3, 'k2': 0.2}}
You can use a dict comprehension to get the last 3 items then use reduce function to create a nested dictionary :
>>> l=[('New Model','v7','k1',0.1),
... ('New Model','v8','k2',0.2),
... ('New Model','v8','k3',0.3)]
>>>
>>> [reduce(lambda x,y:{y:x},p) for p in [i[1:][::-1] for i in l]]
[{'v7': {'k1': 0.1}},
{'v8': {'k2': 0.2}},
{'v8': {'k3': 0.3}}]
This also will works with longer lists :
>>> l=[('New Model','v7','k1',0.1,'c','5','r',9),
... ('New Model','v8','k2',0.2,'d','6'),
... ('New Model','v8','k3',0.3)]
>>> [reduce(lambda x,y:{y:x},p) for p in [i[1:][::-1] for i in l]]
[{'v7': {'k1': {0.1: {'c': {'5': {'r': 9}}}}}},
{'v8': {'k2': {0.2: {'d': '6'}}}},
{'v8': {'k3': 0.3}}]
Edit: If you want a dictionary as the main container you can use a generator expression within dict to convert your list to dictionary :
>>> g=[reduce(lambda x,y:{y:x},p) for p in [i[1:][::-1] for i in l]]
>>> dict(next(i.iteritems()) for i in g)
{'v8': {'k3': 0.3}, 'v7': {'k1': {0.1: {'c': {'5': {'r': 9}}}}}}
Here is a solution, which I believe is easy to understand:
import collections
kinetic_parameters = [
('New Model','v7','k1',0.1),
('New Model','v8','k2',0.2),
('New Model','v8','k3',0.3),
]
result = collections.defaultdict(dict)
for _, outter_key, inner_key, inner_value in kinetic_parameters:
outter_value = {inner_key: inner_value}
result[outter_key].update(outter_value)
In this solution, we use defaultdict for the outer dictionary. The first time we encounter result[outter_key], an empty dictionary will be created and assigned to the value. The next step is to update that value (the inner dictionary).
Update
If you don't want to use defaultdict:
result = {}
for _, outter_key, inner_key, inner_value in kinetic_parameters:
outter_value = {inner_key: inner_value}
result.setdefault(outter_key, {})
result[outter_key].update(outter_value)
The setdefault method create a new dictionary and assign to the outter dictionary only for the first time.
I'm a novice python programmer and I'm stuck on a homework problem.
I want to combine dictionaries (tried using **dict) without using the update() method because I want to keep any duplicate keys. I'm fine with having some keys with multiple values.
Could someone point me in the right direction?
Also, I'm doing this in python 3.3
A dict maps a key to a value. Not multiple values. Thus, you need to make each value in the combined dict be a combination of all the values from the input dicts. The easiest way is to use a collections.defaultdict(list):
import collections
input_dicts = [{1: 0}, {1: 1}, {1: 2}]
output_dict = collections.defaultdict(list)
for d in input_dicts:
for key in d:
output_dict[key].append(d[key])
A collections.defaultdict calls a function you specify to generate a default value for any key that you try to access that doesn't already have a value. A collections.defaultdict(list) is thus a dict with default values of lists for all keys. This code will produce an output dict mapping keys to lists of all values from the input dicts.
You can't have duplicate keys in a dictionary. The keys must be unique, but I think what you're looking for is a defaultdict
from collections import defaultdict
d = defaultdict(list)
d1 = {1:'hi', 2:'hey', 3:'hai'}
d2 = {1:'hello', 2:'cabbage', 3:'greetings'}
for k, v in d1.items():
d[k].append(v)
for k1, v1 in d2.items():
d[k1].append(v1)
print d
Prints:
defaultdict(<type 'list'>, {1: ['hi', 'hello'], 2: ['hey', 'cabbage'], 3: ['hai', 'greetings']})
I have question about Dictionaries in Python.
here it is:
I have a dict like dict = { 'abc':'a', 'cdf':'b', 'gh':'a', 'fh':'g', 'hfz':'g' }
Now i want to get all Key-Elements by the same value and save it in a new dict.
The new Dict should be look like:
new_dict = { 'b':('cdf'), 'a':('abc','gh'), 'g':('fh','hfz')}
If you are fine with lists instead of tuples in the new dictionary, you can use
from collections import defaultdict
some_dict = { 'abc':'a', 'cdf':'b', 'gh':'a', 'fh':'g', 'hfz':'g' }
new_dict = defaultdict(list)
for k, v in some_dict.iteritems():
new_dict[v].append(k)
If you want to avoid the use of defaultdict, you could also do
new_dict = {}
for k, v in some_dict.iteritems():
new_dict.setdefault(v, []).append(k)
Here's a naive implementation. Someone with better Python skills can probably make it more concise and awesome.
dict = { 'abc':'a', 'cdf':'b', 'gh':'a', 'fh':'g', 'hfz':'g' }
new_dict = {}
for pair in dict.items():
if pair[1] not in new_dict.keys():
new_dict[pair[1]] = []
new_dict[pair[1]].append(pair[0])
print new_dict
This produces
{'a': ['abc', 'gh'], 'b': ['cdf'], 'g': ['fh', 'hfz']}
If you do specifically want tuples as the values in your new dictionary, you can still use defaultdict, and use tuple concatenation. This solution works in Python 3.4+:
from collections import defaultdict
source = {'abc': 'a', 'cdf': 'b', 'gh': 'a', 'fh': 'g', 'hfz': 'g'}
target = defaultdict(tuple)
for key in source:
target[source[key]] += (key, )
print(target)
Which will produce
defaultdict(<class 'tuple'>, {'a': ('abc', 'gh'), 'g': ('fh', 'hfz'), 'b': ('cdf',)})
This will probably be slower than generating a dictionary by list insertion, and will create more objects to be collected. So, you can build your dictionary out of lists, and then map it into tuples:
target2 = defaultdict(list)
for key in source:
target2[source[key]].append(key)
for key in target2:
target2[key] = tuple(target2[key])
print(target2)
Which will give the same result as above.
It can be done this way too, without using any extra functions .
some_dict = { 'abc':'a', 'cdf':'b', 'gh':'a', 'fh':'g', 'hfz':'g' }
new_dict = { }
for keys in some_dict:
new_dict[some_dict[keys]] = [ ]
for keys in some_dict:
new_dict[some_dict[keys]].append(keys)
print(new_dict)