I have this dictionary.
'Frank': {'Jack': 0, 'Kevin': 0, 'Sam': 0}
'Sam': {'Frank': 0, 'Jack': 0, 'Kevin': 0}
'Kevin': {'Frank': 0, 'Jack': 0, 'Sam': 0}
'Jack': {'Frank': 0, 'Kevin': 0, 'Sam': 0}
I have the variables speaker and listener. A speaker is the name of the dictionary, and the listener can be one of the keys in the dictionary. For example 'Frank' is the speaker, and 'Jack','Sam' and 'Kevin' could either be a listener in the first dict created. I want to be able to increment the value for a specific listener. For example if speaker = 'Sam' and listener = 'Kevin', I want this to happen
'Sam': {'Frank': 0, 'Jack': 0, 'Kevin': 1}
And vice versa
'Kevin': {'Frank': 0, 'Jack': 0, 'Sam': 1}
Programming and python newbie here. Any help on how to do this would be greatly appreciated! I have been stuck on this for a while. Thanks.
Take a look at this:
d = {
'Frank': {'Jack': 0, 'Kevin': 0, 'Sam': 0},
'Sam': {'Frank': 0, 'Jack': 0, 'Kevin': 0},
'Kevin': {'Frank': 0, 'Jack': 0, 'Sam': 0},
'Jack': {'Frank': 0, 'Kevin': 0, 'Sam': 0} }
d ['Frank'] ['Kevin'] += 1
print (d)
d['Frank'] is the listener dictionary of Frank, and d['Frank']['Kevin'] is how many times Kevin has listened to Frank. This value you can increment.
Or if the speaker-listener relation is symmetrical, you can try this:
def talk (speaker, listener, data):
data[speaker][listener] += 1
data[listener][speaker] += 1
d = {
'Frank': {'Jack': 0, 'Kevin': 0, 'Sam': 0},
'Sam': {'Frank': 0, 'Jack': 0, 'Kevin': 0},
'Kevin': {'Frank': 0, 'Jack': 0, 'Sam': 0},
'Jack': {'Frank': 0, 'Kevin': 0, 'Sam': 0} }
talk('Frank', 'Sam', d)
print(d)
I'd probably create a new Person object, to be honest.
class Person(object):
def __init__(self,name):
self.name = name
def speak(self,other):
for (speaker,listener) in ((self,other),(other,self)):
try: speaker.__dict__[listener.name] += 1
except KeyError: speaker.__dict__[listener.name] = 1
#property
def listeners(self):
return {name:value for name,value in self.__dict__.items() if name != "name"}
## DEMO
>>> Adam = Person("Adam")
>>> Steve = Person("Steve")
>>> Adam.speak(Steve)
>>> Adam.Steve
1
>>> Steve.Adam
1
>>> Paul = Person("Paul")
>>> for listener in [Adam,Steve]:
Paul.speak(listener)
>>> Paul.listeners
{"Adam":1, "Steve":1}
Another approach, mimicking #adsmith's answer, but avoiding tampering with __dict__ and thus making all possible person names permissible.
class Person:
directional = False
def __init__(self, name):
self.name = name
self.listeners = {}
def speak(self, other):
try: self.listeners[other] += 1
except KeyError: self.listeners[other] = 1
if Person.directional: return
try: other.listeners[self] += 1
except KeyError: other.listeners[self] = 1
def __getitem__(self, person):
try: return self.listeners[person]
except KeyError: return 0
def __repr__(self):
return self.name
Sample usage:
alice = Person('Alice')
bob = Person('Bob')
charles = Person('Charles')
alice.speak(bob)
alice.speak(bob)
bob.speak(charles)
print(alice[bob])
print(alice[charles])
print(alice[bob])
print(bob.listeners)
Related
I need to assign 0 and 1 as values to keys in the dictionaries:
combinations_string_list = [num_list_to_str(i) for i in itertools.product([0, 1], repeat=2)]
all_stategy = []
for i in range(16):
strategy_table = {x: y for x in combinations_string_list for y in [0, 1]}
all_stategy.append(strategy_table)
print(all_stategy)
I got [{'00': 1, '01': 1, '10': 1, '11': 1}, {'00': 1, '01': 1, '10': 1, '11': 1}, {'00': 1, '01': 1, '10': 1, '11': 1}, ...]
but I need [{'00': 0, '01': 0, '10': 0, '11': 0}, {'00': 0, '01': 0, '10': 0, '11': 1}, {'00': 0, '01': 0, '10': 1, '11': 0}, ...] instead.
How can I create this kind of value? Thanks!
You can zip the key sequence ["0", "1"] with each element of the cartesian product to produce input to dict:
>>> [dict(zip(["0", "1"], x)) for x in product([0,1], repeat=2)]
[{'0': 0, '1': 0}, {'0': 0, '1': 1}, {'0': 1, '1': 0}, {'0': 1, '1': 1}]
or
>>> values=[0,1]
>>> [dict(zip(map(str, values), x)) for x in product(values, repeat=2)]
rows = []
def rec(diry,level):
if level == 2:
diry['column_{}'.format(level)] = level
rows.append(diry)
else:
diry['column_{}'.format(level)] = level
rows.append(diry)
rec(diry,level+1)
rec({},0)
print(rows)
The above code prints
[{'column_0': 0, 'column_1': 1, 'column_2': 2},
{'column_0': 0, 'column_1': 1, 'column_2': 2},
{'column_0': 0, 'column_1': 1, 'column_2': 2}]
Shouldn't it print
[{'column_0': 0},
{'column_0': 0, 'column_1': 1},
{'column_0': 0, 'column_1': 1, 'column_2': 2}]
Any suggestions will be helpful. Thanks
It is something distracting for beginners. You have to make sure that you pass a copy of dictionary or else it is the same reference to dictionary that you end up modifying:
rec(diry.copy(), level+1)
Code:
rows = []
def rec(diry,level):
if level == 2:
diry['column_{}'.format(level)] = level
rows.append(diry)
else:
diry['column_{}'.format(level)] = level
rows.append(diry)
rec(diry.copy(),level+1) # CHANGE HERE
rec({},0)
print(rows)
I am going from top to bottom but i think it is what you want:
def rec_append(n):
if n == 0:
return [{f'col{n}': n}]
else:
return (rec_append(n-1)) + [{f'col{n}': n for n in range(n+1)}]
print(rec_append(3))
[{'col0': 0},
{'col0': 0, 'col1': 1},
{'col0': 0, 'col1': 1, 'col2': 2},
{'col0': 0, 'col1': 1, 'col2': 2, 'col3': 3}]
You are changing the dictionary in your iterations and inserting a reference to it in the list. At the end you have inserted three times the reference to the same dictionary and therefore the last print is just three printing outputs of the same dictionary.
If you really want to have each time a reference to the dictionary at that time you have to make a copy:
rows = []
import copy
def rec(diry,level):
if level == 2:
diry['column_{}'.format(level)] = level
rows.append(diry)
else:
diry['column_{}'.format(level)] = level
rows.append(copy.deepcopy(diry))
rec(diry,level+1)
rec({},0)
print(rows)
Output:
[{'column_0': 0}, {'column_0': 0, 'column_1': 1}, {'column_0': 0, 'column_1': 1, 'column_2': 2}]
You can change your code to this to get the desired output:-
rows = []
def rec(diry,level):
if level == 2:
diry['column_{}'.format(level)] = level
# print(diry)
rows.append(diry)
print(diry)
else:
diry['column_{}'.format(level)] = level
rows.append(diry)
print(diry)
rec(diry,level+1)
rec({},0)
Output:-
{'column_0': 0}
{'column_0': 0, 'column_1': 1}
{'column_0': 0, 'column_1': 1, 'column_2': 2}
Now you can compare this code and your code to get the intuition of why you are getting the result you were thinking.
Given the following code:
minimal example of list of lists:
c = [['dog', 'Sg', 'Good'], ['cat', 'Pl', 'Okay'], ['dog', 'Pl', 'Bad'],
['dog', 'Sg', 'Good'], ['cat', 'Pl', 'Okay'], ['dog', 'Pl', 'Okay'],
['dog', 'Sg', 'Good'], ['cat', 'Sg', 'Good'], ['dog', 'Pl', 'Bad'],
['dog', 'Sg', 'Good'], ['cat', 'Pl', 'Okay'], ['dog', 'Pl', 'Bad']]
create sets of words from c
outer_keys = set()
inner_keys = set()
for x in c:
outer_keys.add(x[0])
inner_keys |= set(x[1:])
create dict with for loop
Lemma = dict()
for i in outer_keys:
j_d = dict()
for j in inner_keys:
j_d[j] = 0
j_d[i] = 0 # this is the line I can't replicate with a comprehension
Lemma[i] = j_d
for loop result:
{'dog': {'Okay': 0, 'Pl': 0, 'Good': 0, 'Bad': 0, 'Sg': 0, 'dog': 0},
'cat': {'Okay': 0, 'Pl': 0, 'Good': 0, 'Bad': 0, 'Sg': 0, 'cat': 0}}
using dict comprehension:
This is where I need assistance. I haven't been able to replicate the for-loop with the dict comprehension
Lemma = {j: {i: 0 for i in inner_keys} for j in outer_keys}
Note: dog should be inside the value of outer dog and the same for cat
My dict comprehension result:
{'dog': {'Okay': 0, 'Pl': 0, 'Good': 0, 'Bad': 0, 'Sg': 0},
'cat': {'Okay': 0, 'Pl': 0, 'Good': 0, 'Bad': 0, 'Sg': 0}}
Question:
How can I replicate the result of the for-loop with the dict comprehension?
Order doesn't matter.
You can use dict.fromkeys together with inner_keys | {j}:
>>> {j: dict.fromkeys(inner_keys | {j}, 0) for j in outer_keys}
{'cat': {'Bad': 0, 'Good': 0, 'Okay': 0, 'Pl': 0, 'Sg': 0, 'cat': 0},
'dog': {'Bad': 0, 'Good': 0, 'Okay': 0, 'Pl': 0, 'Sg': 0, 'dog': 0}}
Just create a new dict from your inner dict
>>> {j: dict({i: 0 for i in inner_keys}, **{j:0}) for j in outer_keys}
{'dog': {'Bad': 0, 'Good': 0, 'Okay': 0, 'Sg': 0, 'dog': 0, 'Pl': 0}, 'cat': {'Bad': 0, 'Good': 0, 'Okay': 0, 'Sg': 0, 'Pl': 0, 'cat': 0}}
I got something like this:
> d1 = {'System tests': {'failed': 5, 'passed': 0, 'total': 5},
'Func tests': {'failed': 5, 'passed': 0, 'total': 5}}
> d2 = {'System tests': {'failed': 1, 'passed': 1, 'total': 2},
'Func tests': {'failed': 3, 'passed': 2, 'total': 5}}
> d3 = {'System tests': {'failed': 0, 'passed': 0, 'total': 0},
'Func tests': {'failed': 1, 'passed': 0, 'total': 1}}
I would like to sum values 'failed', passed and total into one dictionary
so the output should be like this:
d4 = {'System tests': {'failed': 6, 'passed': 1, 'total': 7},
'Func tests': {'failed': 9, 'passed': 2, 'total': 11}
What is the easiest solution to do such thing?
I can use basic libraries, except collections.
The solution must be generic, for example if some other dictionaries would appear in the future
input:
d1 = {'a': 100, 'b': 200, 'c':300}
d2 = {'a': 300, 'b': 200, 'd':400}
d = {k : d1.get(k, 0) + d2.get(k,0) for k in set(d1.keys()) | set(d2.keys())}
Output:
{'a': 400, 'b': 400, 'c': 300, 'd': 400}
Using Counter and defaultdict that is fairly straight forward like:
Code:
d4 = defaultdict(Counter)
for d in d1, d2, d3:
for k, subd in d.items():
d4[k].update(subd)
Test Code:
d1 = {'System tests': {'failed': 5, 'passed': 0, 'total': 5},
'Func tests': {'failed': 5, 'passed': 0, 'total': 5}}
d2 = {'System tests': {'failed': 1, 'passed': 1, 'total': 2},
'Func tests': {'failed': 3, 'passed': 2, 'total': 5}}
d3 = {'System tests': {'failed': 0, 'passed': 0, 'total': 0},
'Func tests': {'failed': 1, 'passed': 0, 'total': 1}}
from collections import Counter, defaultdict
d4 = defaultdict(Counter)
for d in d1, d2, d3:
for k, subd in d.items():
d4[k].update(subd)
print(d4)
Results:
defaultdict(<class 'collections.Counter'>, {
'System tests': Counter({'total': 7, 'failed': 6, 'passed': 1}),
'Func tests': Counter({'total': 11, 'failed': 9, 'passed': 2})
})
This will give you the output you are looking for, with no libraries.
d4 = {}
for d in d1, d2, d3:
for test, results in d.items():
if test not in d4:
d4[test] = {}
for key, value in results.items():
if key in d4[test]:
d4[test][key] += value
else:
d4[test][key] = value
Result:
{'System tests': {'failed': 6, 'passed': 1, 'total': 7}, 'Func tests': {'failed': 9, 'passed': 2, 'total': 11}}
If you cannot use collections.Counter, another solution is to use reduce
from functools import reduce # reduce was moved here in Python3
def add_dicts(dict_list):
def add(fst, snd):
return {k: fst[k] + snd[k] for k in fst}
return reduce(add, dict_list[1:], dict_list[0])
Using this in your code would look like this.
dict_list = [d1, d2, d3]
d4 = {}
for k in dict_list[0]:
d4[k] = add_dicts([d[k] for d in dict_list])
Although, this assumes all your dict are correctly formated.
You can use zip along with dict.items:
d1 = {'System tests': {'failed': 5, 'passed': 0, 'total': 5},
'Func tests': {'failed': 5, 'passed': 0, 'total': 5}}
d2 = {'System tests': {'failed': 1, 'passed': 1, 'total': 2},
'Func tests': {'failed': 3, 'passed': 2, 'total': 5}}
d3 = {'System tests': {'failed': 0, 'passed': 0, 'total': 0},
'Func tests': {'failed': 1, 'passed': 0, 'total': 1}}
def combine_dicts(*d):
return {a:{i:sum(h[i] for h in [b, c, d]) for i in ['failed', 'passed', 'total']} for [a, b], [_, c], [_, d] in zip(*d)}
print(combine_dicts(d1.items(), d2.items(), d3.items()))
Output:
{'System tests': {'failed': 6, 'total': 7, 'passed': 1}, 'Func tests': {'failed': 9, 'total': 11, 'passed': 2}}
I have this list of names: [Frank, Sam, Kevin, Jack]
Is it possible to create a dictionary using the names in the list to create something like this?
'Frank' : {'Sam': 0, 'Kevin': 0, 'Jack': 0},
'Sam' : {'Frank': 0, 'Kevin': 0, 'Jack': 0},
'Kevin' : {'Frank': 0, 'Sam': 0, 'Jack': 0}
'Jack' : {'Frank': 0, 'Sam': 0, 'Kevin': 0}
I want to know if it's possible to iterate through the list, pick the first name and then create a dictionary with it, with the other members in the list as keys and 0 as the default value. And then repeat it for the other elements in the list as well.
I was thinking of using something like this.
my_dynamic_vars = dict()
my_dynamic_vars.update({string: dict()})
Any help would be much appreciated.
You can use nested dictionary comprehensions:
>>> lst = ['Frank', 'Sam', 'Kevin', 'Jack']
>>> dct = {x:{y:0 for y in lst if y != x} for x in lst}
>>> dct
{'Frank': {'Kevin': 0, 'Sam': 0, 'Jack': 0}, 'Kevin': {'Frank': 0, 'Jack': 0, 'Sam': 0}, 'Sam': {'Frank': 0, 'Jack': 0, 'Kevin': 0}, 'Jack': {'Frank': 0, 'Kevin': 0, 'Sam': 0}}
>>>
>>> # Just to demonstrate
>>> from pprint import pprint
>>> pprint(dct)
{'Frank': {'Jack': 0, 'Kevin': 0, 'Sam': 0},
'Jack': {'Frank': 0, 'Kevin': 0, 'Sam': 0},
'Kevin': {'Frank': 0, 'Jack': 0, 'Sam': 0},
'Sam': {'Frank': 0, 'Jack': 0, 'Kevin': 0}}
>>>
ummm
d= {}
names = ["Frank","Sam","Kevin","Jack"]
for name in names:
d[name] = dict.fromkeys(set(names).difference([name]),0)
print d
is probably how I would do it ..
names = ['Frank', 'Sam', 'Kevin', 'Jack']
d = dict.fromkeys(names, 0)
names_dict = {}
for name in names:
temp = d.copy()
del temp[name]
names_dict.update([(name, temp)])
output:
>>> for d in names_dict:
>>> print d
'Frank': {'Jack': 0, 'Kevin': 0, 'Sam': 0}
'Sam': {'Frank': 0, 'Jack': 0, 'Kevin': 0}
'Kevin': {'Frank': 0, 'Jack': 0, 'Sam': 0}
'Jack': {'Frank': 0, 'Kevin': 0, 'Sam': 0}
names = ['Frank', 'Sam', 'Kevin', 'Jack']
d = {name: dict.fromkeys([x for x in names if x != name], 0)
for name in names}
from pprint import pprint
pprint(d)
Output
{'Frank': {'Jack': 0, 'Kevin': 0, 'Sam': 0},
'Jack': {'Frank': 0, 'Kevin': 0, 'Sam': 0},
'Kevin': {'Frank': 0, 'Jack': 0, 'Sam': 0},
'Sam': {'Frank': 0, 'Jack': 0, 'Kevin': 0}}