same output in values for different keys in for-loop - python

I'm new to Python and was trying to create a new dictionary from a dictionary with values in list format. Below please find my code:
dataset = {
"a" : [3, 1, 7, 5, 9],
"b" : [4, 8, 7, 5, 3],
"c" : [3, 4, 1, 0, 0],
"d" : [0, 5, 1, 5, 5],
"e" : [3, 7, 5, 5, 1],
"f" : [3, 6, 9, 2, 0],
}
for v in dataset.values():
total = (sum(v))
print(total)
for k in dataset:
print(k)
dict1 = {k:total for k in dataset}
print(dict1)
My expected result is {"a":25, "b":27, ..}.
Instead, when i run the codes, the output is
{'a': 20, 'b': 20, 'c': 20, 'd': 20, 'e': 20, 'f': 20}
May I know which part of the codes I am wrong?

It's because total is set to the last value in your for v in dataset.values() loop. You should try
dict1={k: sum(v) for k,v in dataset.items()}

You are just storing the last total in your solution. Try doing this instead:
dataset = {
"a" : [3, 1, 7, 5, 9],
"b" : [4, 8, 7, 5, 3],
"c" : [3, 4, 1, 0, 0],
"d" : [0, 5, 1, 5, 5],
"e" : [3, 7, 5, 5, 1],
"f" : [3, 6, 9, 2, 0],
}
dict1 = {k: sum(v) for k, v in dataset.items()}
print(dict1)

'total' changes after each iteration. Every time you go through a value in your dictionary and take the sum, you get a new total. So when the loop ends, total is the sum of the last list in your dictionary.
You are making each key in your dictionary have the value of the total for the last list. Instead, you should assign the total for each key inside the loop you are calculating total.

try this one.
dataset = {
"a" : [3, 1, 7, 5, 9],
"b" : [4, 8, 7, 5, 3],
"c" : [3, 4, 1, 0, 0],
"d" : [0, 5, 1, 5, 5],
"e" : [3, 7, 5, 5, 1],
"f" : [3, 6, 9, 2, 0],
}
result = {}
for (k, v) in dataset.items():
result[k] = sum(v)
print (result)
output:
{'a': 25, 'c': 8, 'b': 27, 'e': 21, 'd': 16, 'f': 20}

You are setting total once for every list of values in dataset, but by the time you use dictionary comprehension to create your dict1, you're only using the last calculated value of total, which happens to be 20. (Dicts are not ordered, so total could have ended with any of your sum values, depending on which random order the values were visited in.)
Instead, you can do all of this in one line, using a handy function called items(), which turns a dict into a list of pairs (i.e.: 2-tuples) of corresponding keys and values. So you can rewrite your dict1 code like this:
dict1 = {k: sum(v) for (k, v) in dataset.items()}

When you run the following part of your code, the total is updated for every value in the dataset dictionary, and then the total is updated to the sum of the last element of the dictionary, i.e. [3, 6, 9, 2, 0], hence total=20
for v in dataset.values():
total = (sum(v))
print(total)
And then when you do dict1 = {k:total for k in dataset}, all values of dict1 are 20`.
Two ways to simplify this.
Iterate through the input dictionary and update the output dictionary at the same time, this is most efficient
total = []
dict1 = {}
for k, v in dataset.items():
total = sum(v)
dict1[k] = total
print(dict1)
#{'a': 25, 'b': 27, 'c': 8, 'd': 16, 'e': 21, 'f': 20}
Iterate through the values, and then make a list of all the sums, and then iterate through the keys, and make the output dictionary. Note that this is grossly inefficient, but can be treated as the intermediate step from going to the code you currently have, to the first approach.
total = []
dict1 = {}
#Create the list of sums
for v in dataset.values():
total.append(sum(v))
idx = 0
#Use that list of sums to create the output dictionary
for k in dataset.keys():
dict1[k] = total[idx]
idx+=1
print(dict1)
#{'a': 25, 'b': 27, 'c': 8, 'd': 16, 'e': 21, 'f': 20}

Related

How to add elements of python lists in a dictionary

Below is list of arrays:
{'array_1': [1, 2, 3, 4], 'array_2': [3, 4, 5, 6], 'array_3': [7, 8, 9, 0]}
Code for array input:
def main():
a = int(input("Enter the number of array's: "))
size = int(input('Each array size: '))
arrays = dict()
for i in range(1, a + 1):
arrays['array_' + str(i)] = list(
map(lambda j: int(input('value: ')), [j for j in range(size)]))
print(arrays)
I want to add 'array_1' with array_2
Just for clarification, you have a dictionary of lists, not a list of arrays. I think this is what you're looking for
list_dict = {'array_1': [1, 2, 3, 4], 'array_2': [3, 4, 5, 6], 'array_3': [7, 8, 9, 0]}
[sum(items) for items in zip(list_dict['array_1'], list_dict['array_2'])]
this results in the list [4, 6, 8, 10] - I'm assuming that's what you mean by add array_1 and array_2
If by add you mean concatenate do this:
new_list = array['array_1'] + array['array_2']
else if you mean addition of individual values you can do:
from operator import add
new_array = list(map(add,array['array_1'],array['array_2']))
If you want to sum element wise then
d= {'array_1': [1, 2, 3, 4], 'array_2': [3, 4, 5, 6], 'array_3': [7, 8, 9, 0]}
[sum(x) for x in zip(*d.values())] # will add elements from all the lists
Output:
[11, 14, 17, 10]
going along the same lines if you just want to add lists corresponding to some keys then you can filter the keys to create a new dict and use it in a same way
[sum(x) for x in zip(*{key:value for key,value in d.items() if key in ['array_1','array_2']}.values())]
Output
[4, 6, 8, 10]

For loop giving different results for user-entered list vs a hard coded list

Basically I have dictionary with each key-pair having its value as a list. Reason, is so that I can insert or append additional values into the list later on.
Like this, each key pair is:
'A' : [2]
To make testing code faster, I hard coded a portion of the playerDict like this:
playerDict = {"A" : [2], "B" : [2], "C" : [2]}
I also allowed a way to enter additional key-pairs. So I can manually enter additional key-pair 'D' and 'E'
{'A': [2], 'B': [2], 'C': [2], 'D': [2], 'E': [2]}
Looks exactly the same when I print out the playerDict. However, behaviour is different when I run it through a for loop to insert/append values into the list.
{'A': [2, 5, 1, 4], 'B': [2, 6, 5, 1], 'C': [2, 6, 5, 1], 'D': [2, 8, 6, 1, 5, 5, 3], 'E': [2, 8, 6, 1, 5, 5, 3]}
Behaviour for A, B and C is what I want, which is only 1 insertion at index 1 of the list and 2x appending at the end of the list for each key-pair.
However, for the manually entered key-pair, it gets inserted and appended how many times I manually placed a key-pair in. Place in 2 key-pair, 2 times, place in 3 key-pair, it gets inserted and appended 3 times.
{'A': [2, 6, 2, 4], 'B': [2, 3, 1, 2], 'C': [2, 6, 4, 2], 'D': [2, 9, 10, 11, 5, 6, 4, 6,6, 3], 'E': [2, 9, 10, 11, 5, 6, 4, 6, 6, 3], 'F': [2, 9, 10, 11, 5, 6, 4, 6, 6, 3]}
Its driving me nuts since I'm unsure what is the difference between my hard-coded key-pairs and the manually entered ones. How can I get my desired behaviour?
import random
def rollDice():
return random.randint(1, 6)
def getPlayers(playerDict):
points = [2]
while True:
name = str(input("Enter player name, <Enter> to end: "))
if name == "":
break
else:
playerDict[name] = points
print(playerDict, "adding a user")
return playerDict
def startGame(playerDict):
print("Start game. Roll 2 dice per player")
for names, stats in playerDict.items():
rollstart1 = rollDice()
rollstart2 = rollDice()
total = rollstart1 + rollstart2
stats.insert(1, total)
stats.append(rollstart1)
stats.append(rollstart2)
print("{}, dice: ({}, {}), total {}".format(names, stats[2], stats[3], stats[1]))
return playerDict
def main():
#playerDict = {}
playerDict = {"A" : [2], "B" : [2], "C" : [2]}
playerDict = getPlayers(playerDict)
playerDict = startGame(playerDict)
print(playerDict)
main()
You want a fresh new list for each player... not the same list for all of them; changing the code to
playerDict[name] = [2]
should do the trick.
It is important to understand that with Python assignment doesn't copy objects. If you want to make a copy you need to ask explicitly so:
a = [2]
b = a
a.append(12)
print(b) # will print [2, 12] because a and b reference the same list object
In Python the "list literal" [2] isn't indeed a list... but a "list constructor" that creates a new separate list object each time is evaluated.

Compare Integers between Lists in a Dictionary

I'm new to Python and I am trying to make a calculator for a game. I would like to get the max integer at a specific index between lists (that are values in the dictionary) and the key that the max value came from.
I've tried to loop through the dictionary.
raw_player_score = {'Matt' : [3, 5, 5, 4, 6, 9],
'Kyle' : [6, 9, 11, 5, 4, 3],
'Emily' : [4, 4, 5, 2, 1, 5]}
def extra_points(dict):
for k, v in dict.items():
for number in v:
apple_king = max(v[1])
print(apple_king)
final_dict = extra_points(raw_player_score)
I would expect the outcome to be 9 since Kevin has the highest number at index 1, but instead, I get the message "'int' object is not iteratable'
All of the suggestions in the other answers are spot on. I'll offer up a simpler, old-school solution that does the minimal amount of work, not having to create any additional lists or do any sorting. I figure that as a new Python programmer, you might be best served by the most direct and transparent approach:
raw_player_scores = {'Matt' : [3, 5, 5, 4, 6, 9],
'Kyle' : [6, 9, 11, 5, 4, 3,],
'Emily' : [4, 4, 5, 2, 1, 5]}
def extra_points(scores, pos):
max_score = 0
max_key = None
for k, v in scores.items():
if v[pos] > max_score:
max_score = v[pos]
max_key = k
return max_key
max_key = extra_points(raw_player_scores, 1)
print(max_key)
Result:
Kyle
It is not good idea to hardcode the needed index; I recommend you to move it to an argument. Other changes are commented:
def extra_points(dict_, index):
return max( # Return maximum
( # From iterator
(name, score_list[index]) # For name-score[index] tuples
for name, score_list in dict_.items() # In dict_
),
key=lambda x: x[1] # Check the max by score[index]
)[0] # Get the name (zero element)
raw_player_score = {
'Matt': [3, 5, 5, 4, 6, 9],
'Kyle': [6, 9, 11, 5, 4, 3,],
'Emily': [4, 4, 5, 2, 1, 5]
}
print(extra_points(raw_player_score, 1))
Kyle
Try not to use dict as a variable name, you can try:
raw_player_score = {'Matt': [3, 5, 5, 4, 6, 9], 'Kyle': [6, 9, 11, 5, 4, 3], 'Emily': [4, 4, 5, 2, 1, 5]}
def extra_points(d, ind):
values_at_index = []
for key in d:
values_at_index.append((key, d[key][ind]))
return max(values_at_index, key=lambda x: x[1])
print(extra_points(raw_player_score, 1))
print(extra_points(raw_player_score, 1)[0])
which gives:
('Kyle', 9)
Kyle

Sum tuples of cartesian product of arbitrary number of dicts

I'd like to do the cartesian product of multiple dicts, based on their keys, and then sum the produced tuples, and return that as a dict. Keys that don't exist in one dict should be ignored (this constraint is ideal, but not necessary; i.e. you may assume all keys exist in all dicts if needed). Below is basically what I'm trying to achieve (example shown with two dicts). Is there a simpler way to do this, and with N dicts?
def doProdSum(inp1, inp2):
prod = defaultdict(lambda: 0)
for key in set(list(inp1.keys())+list(inp2.keys())):
if key not in prod:
prod[key] = []
if key not in inp1 or key not in inp2:
prod[key] = inp1[key] if key in inp1 else inp2[key]
continue
for values in itertools.product(inp1[key], inp2[key]):
prod[key].append(values[0] + values[1])
return prod
x = doProdSum({"a":[0,1,2],"b":[10],"c":[1,2,3,4]}, {"a":[1,1,1],"b":[1,2,3,4,5]})
print(x)
Output (as expected):
{'c': [1, 2, 3, 4], 'b': [11, 12, 13, 14, 15], 'a': [1, 1, 1, 2, 2, 2,
3, 3, 3]}
You can do it like this, by first reorganizing your data by key:
from collections import defaultdict
from itertools import product
def doProdSum(list_of_dicts):
# We reorganize the data by key
lists_by_key = defaultdict(list)
for d in list_of_dicts:
for k, v in d.items():
lists_by_key[k].append(v)
# list_by_key looks like {'a': [[0, 1, 2], [1, 1, 1]], 'b': [[10], [1, 2, 3, 4, 5]],'c': [[1, 2, 3, 4]]}
# Then we generate the output
out = {}
for key, lists in lists_by_key.items():
out[key] = [sum(prod) for prod in product(*lists)]
return out
Example output:
list_of_dicts = [{"a":[0,1,2],"b":[10],"c":[1,2,3,4]}, {"a":[1,1,1],"b":[1,2,3,4,5]}]
doProdSum(list_of_dicts)
# {'a': [1, 1, 1, 2, 2, 2, 3, 3, 3],
# 'b': [11, 12, 13, 14, 15],
# 'c': [1, 2, 3, 4]}

working out an average of the values in a dictionary

My dictionary as of now is like this:
class_1 = {'Bob':[9,5,4,3,3,4], 'John':[5,5,7,3,6], 'Andy':[7,5,6,4,5], 'Harris':[3,4,2,3,2,3,2]}
What i am trying to make it look like is this:
class_1_average ={'Bob':[average of scores],'John':[average of scores].........
How can i do this so that even when the scores updates the average also updates with it. And is there also a way to find the highest score out of the scores
try like this:
class_1_average = {key: sum(value)/len(value) for key, value in class_1.items()}
For max value: you can use max built-in function over the value of dictionary
max_each = {key: max(value) for key, value in class_1.items()}
You can use numpy.mean in a generator expression to get the average for each student. You can use this paradigm in general to get other statistics.
>>> from numpy import mean
>>> class_1 = {'Bob':[9,5,4,3,3,4], 'John':[5,5,7,3,6], 'Andy':[7,5,6,4,5], 'Harris':[3,4,2,3,2,3,2]}
>>> class_1_average = {name: mean(values) for name, values in class_1.items()}
>>> class_1_average
{'John': 5.2000000000000002, 'Harris': 2.7142857142857144, 'Andy': 5.4000000000000004, 'Bob': 4.666666666666667}
One thing that comes to mind if you need to keep your averages updated "in real time" (although is probably killing flies with nuclear weapons and not really what you need) would be creating a custom class that inherits from the builtin dict type and extend it with an averages method:
import pprint
class MyDict(dict):
def averages(self):
averages = {}
for name, score_list in self.iteritems():
averages[name] = sum(score_list) / len(score_list)
return averages
if __name__ == "__main__":
class_1 = MyDict({
'Bob': [9, 5, 4, 3, 3, 4],
'John': [5, 5, 7, 3, 6],
'Andy': [7, 5, 6, 4, 5],
'Harris': [3, 4, 2, 3, 2, 3, 2]
})
print "class_1: %s" % pprint.pformat(class_1)
print "class_1_averages: %s" % pprint.pformat(class_1.averages())
print "Bob's average: %s" % pprint.pformat(class_1.averages()['Bob'])
print "Setting Bob's scores to [1, 1, 1]"
class_1['Bob'] = [1, 1, 1]
print "Bob's average: %s" % pprint.pformat(class_1.averages()['Bob'])
That outputs:
class_1: {'Andy': [7, 5, 6, 4, 5],
'Bob': [9, 5, 4, 3, 3, 4],
'Harris': [3, 4, 2, 3, 2, 3, 2],
'John': [5, 5, 7, 3, 6]}
class_1_averages: {'Andy': 5, 'Bob': 4, 'Harris': 2, 'John': 5}
Bob's average: 4
Setting Bob's scores to [1, 1, 1]
Bob's average: 1
Maybe you can use this as an idea of what Python allows you to do (which doesn't necessarily mean that you should be doing it this way) You're probably much better off with Hackaholic's answer.

Categories

Resources