I am trying to implement a simple task. I have a dictionary with keys (ti, wi)
y={('t1', 'w1'): 1, ('t2', 'w1'): 2, ('t3', 'w1'): 3, ('t1', 'w2'): 4, ('t2', 'w2'): 5, ('t3', 'w2'): 6}
I want to create a new dictionary where keys will be wi
, and value is a list of all ti
. So I want to have an output dictionary like:
{'w1': [1, 2, 3], 'w2': [4, 5, 6]}
I wrote the following code:
y={('t1', 'w1'): 1, ('t2', 'w1'): 2, ('t3', 'w1'): 3, ('t1', 'w2'): 4, ('t2', 'w2'): 5, ('t3', 'w2'): 6}
y_w={}
y_t=[]
for w in range(1,3):
y_t.clear()
for t in range(1,4):
print('t= ', t, 'w= ', w, 'y=' , y['t{0}'.format(t), 'w{0}'.format(w)])
y_t.append(y['t{0}'.format(t), 'w{0}'.format(w)])
print(y_t)
y_w['w{0}'.format(w)]=y_t
print(y_w)
But the result I am getting is
{'w1': [4, 5, 6], 'w2': [4, 5, 6]}
I can not understand where the first list disappeared? Can someone help me explain where I am wrong? Is there a nicer way to do it, maybe without for lops?
CodePudding user response:
Your problem lies in the assumption that setting the value in the dictionary somehow freezes the list.
It's no accident the lists have the same values: They are identical, two pointers to the same list. Observe:
>>> a_dict = {}
>>> a_list = []
>>> a_list.append(23)
>>> a_dict["a"] = a_list
>>> a_list.clear()
>>> a_list.append(42)
>>> a_dict["b"] = a_list
>>> a_dict
{'a': [42], 'b': [42]}
You could fix your solution by replacing y_t.clear()
with y_t = []
, which does create a new list:
y = {('t1', 'w1'): 1, ('t2', 'w1'): 2, ('t3', 'w1'): 3, ('t1', 'w2'): 4, ('t2', 'w2'): 5, ('t3', 'w2'): 6}
y_w = {}
for w in range(1,3):
y_t = []
for t in range(1,4):
print('t= ', t, 'w= ', w, 'y=' , y['t{0}'.format(t), 'w{0}'.format(w)])
y_t.append(y['t{0}'.format(t), 'w{0}'.format(w)])
print(y_t)
y_w['w{0}'.format(w)]=y_t
print(y_w)
But there are, as you suspect, easier ways of doing this, for example the defaultdict
solution shown by Riccardo Bucco.
CodePudding user response:
Try this:
from collections import defaultdict
d = defaultdict(list)
for k, v in y.items():
d[k[1]].append(v)
d = dict(d)
CodePudding user response:
The line number 10 is causing the problem, if you replace it with y_t = []
it will work as you expect
CodePudding user response:
You could first find all unique keys:
unique_keys = set(list(zip(*k))[1])
and then create the dict with list-values using those:
{u: [v for k, v in y.items() if k[1] == u] for u in unique_keys}
CodePudding user response:
According to your output here's what you can try:
y = {('t1', 'w1'): 1, ('t2', 'w1'): 2, ('t3', 'w1'): 3, ('t1', 'w2'): 4, ('t2', 'w2'): 5, ('t3', 'w2'): 6}
def new_dict_with_keys(dictionary):
new_dictionary = dict()
# Go through the dictionary keys to read each key's value
for tuple_key in dictionary:
if "w1" in tuple_key or "w2" in tuple_key:
# Determine which key to use
if "w1" in tuple_key:
key = "w1"
else:
key = "w2"
# Check if the new dictionary has the "w1" or "w2" as a an item
# If it does not, create a new list
if new_dictionary.get(key) is None:
new_dictionary[key] = list()
# Append the value in the respective key
new_dictionary[key].append(dictionary[tuple_key])
# Return the dictionary with the items
return new_dictionary
print(new_dict_with_keys(y))
# Prints: {'w1': [1, 2, 3], 'w2': [4, 5, 6]}
CodePudding user response:
Here's a solution using itertools.groupby
:
import itertools as it
from operator import itemgetter
items = sorted((k, v) for (_, k), v in y.items())
groups = it.groupby(items, key=itemgetter(0))
result = {k: [v for _, v in vs] for k, vs in groups}
# {'w1': [1, 2, 3], 'w2': [4, 5, 6]}