I like to form a dictionary with two lists, header as the key and score as the values:
#data
header= ["math","science","english"]
score = [80,95,75,81,22,90,20,55,99]
#my attempt
d={}
for i in header:
print(i)
for j in score:
print(j)
Desired output is
{("math":80, 81, 20),("science":95,22,55),("english":75,90,99)}
>>> {k: score[i::3] for i, k in enumerate(header)}
{'math': [80, 81, 20], 'science': [95, 22, 55], 'english': [75, 90, 99]}
We can make use of zip in this scenario.
groups = [score[i::3] for i in range(0, len(header))]
dict(zip(header, groups))
{'english': [75, 90, 99], 'math': [80, 81, 20], 'science': [95, 22, 55]}
Assuming you want your output to be a valid dictionary. Then try this.
dict(zip(header,zip(*[score[i:i+3] for i in range(0,len(score),3)])))
# {'math': (80, 81, 20), 'science': (95, 22, 55), 'english': (75, 90, 99)}
You have:
>>> header= ["math","science","english"]
>>> score = [80,95,75,81,22,90,20,55,99]
The first idea is to use zip, but zip stops when the shortest of the two lists is exhausted:
>>> dict(zip(header, score))
{'math': 80, 'science': 95, 'english': 75}
You have to use a second zip to group the scores:
>>> n = len(header)
>>> L = list(zip(*(score[i*n:(i+1)*n] for i in range(n))))
>>> L
[(80, 81, 20), (95, 22, 55), (75, 90, 99)]
And then to zip the header and the grouped scores:
>>> dict(zip(header, L))
{'math': (80, 81, 20), 'science': (95, 22, 55), 'english': (75, 90, 99)}
You should try to divide your problem into multiple smaller problems. Here are two links to related questions and their answers here on Stack Overflow:
How to Split Python list every Nth element
Choose one of the multiple possible solutions for a slice_per function there, so you'll get:
>>> header = ["math", "science", "english"]
>>> score = [80, 95, 75, 81, 22, 90, 20, 55, 99]
>>> def slice_per(source, step):
... return [source[i::step] for i in range(step)]
...
>>> slice_per(score, len(header))
[[80, 81, 20], [95, 22, 55], [75, 90, 99]]
Convert two lists into a dictionary
Combine the slices with your headers:
>>> dict(zip(header, slice_per(score, len(header))))
{'math': [80, 81, 20], 'science': [95, 22, 55], 'english': [75, 90, 99]}
you could use a dictionary comprehension and the buil-in function and enumerate:
step = len(header)
{k : score[i::step] for i, k in enumerate(header)}
output:
{'math': [80, 81, 20], 'science': [95, 22, 55], 'english': [75, 90, 99]}
or you can use numpy:
import numpy as np
dict(zip(header, np.array(score).reshape(3,3).T.tolist()))
output:
{'math': [80, 81, 20], 'science': [95, 22, 55], 'english': [75, 90, 99]}
if you want to use for loops:
result = {}
for i in range(len(score) // len(header)):
for j, h in enumerate(header):
result.setdefault(h, []).append(score[i * len(header) + j])
result
output:
{'math': [80, 81, 20], 'science': [95, 22, 55], 'english': [75, 90, 99]}
Related
I have a list of key:
list_date = ["MON", "TUE", "WED", "THU","FRI"]
I have many lists of values that created by codes below:
list_value = list()
for i in list(range(5, 70, 14)):
list_value.append(list(range(i, i+10, 3)))
Rules created that:
first number is 5, a list contains 4 items has value equal x = x + 3, and so on [5, 8, 11,1 4]
the first number of the second list equal: x = 5 + 14, and value inside still as above x = x +3
[[5, 8, 11, 14], [19, 22, 25, 28], [33, 36, 39, 42], [47, 50, 53, 56], [61, 64, 67, 70]]
I expect to obtain a dict like this:
collections = {"MON":[5, 8, 11, 14], "TUE" :[19, 22, 25, 28], "WED":[33, 36, 39, 42], "THU":[47, 50, 53, 56], "FRI":[61, 64, 67, 70]}
Then, I used:
zip_iterator = zip(list_date, list_value)
collections = dict(zip_iterator)
To get my expected result.
I tried another way like using lambda function
for i in list(range(5, 70, 14)):
list_value.append(list(range(i,i+10,3)))
couple_start_end[lambda x: x in list_date] = list(range(i, i + 10, 3))
And the output is:
{<function <lambda> at 0x000001BF7F0711F0>: [5, 8, 11, 14], <function <lambda> at 0x000001BF7F071310>: [19, 22, 25, 28], <function <lambda> at 0x000001BF7F071280>: [33, 36, 39, 42], <function <lambda> at 0x000001BF7F0710D0>: [47, 50, 53, 56], <function <lambda> at 0x000001BF7F0890D0>: [61, 64, 67, 70]}
I want to ask there is any better solution to create lists of values with the rules above? and create the dictionary collections without using the zip method?
Thank you so much for your attention and participation.
Sure, you can use enumerate but I wouldn't say it is in anyway better or worse than the zip based solution:
collections = {}
for idx, key in enumerate(list_keys):
collections[key] = list_value[idx]
print(collections)
Output:
{'MON': [5, 8, 11, 14], 'TUE': [19, 22, 25, 28], 'WED': [33, 36, 39, 42], 'THU': [47, 50, 53, 56], 'FRI': [61, 64, 67, 70]}
Further, you don't need to create the value list separately, you can create the dictionary as you go along:
list_keys = ["MON", "TUE", "WED", "THU","FRI"]
collections = {}
for idx, start in enumerate(range(5, 70, 14)):
collections[list_keys[idx]] = [i for i in range(start, start+10, 3)]
print(collections)
I got the following list that contains 4 tuples with the scores of each player over 7 games:
players_score = [ ('Joe', 100, 34, 38, 90, 67, 3, 10),
('Bob', 90, 38, 4, 100, 60, 4, 11),
('May', 80, 36, 40, 91, 70, 2, 12),
('Anna', 95, 32, 36, 92, 68, 8, 13) ]
Since I'm trying to learn more about dictionaries, I asked how I could convert the above to a dictionary. I got the following:
# convert player's scores to dictionary
games = {}
for (player_name, *scores) in players_score:
for game_no, score in enumerate(scores, 1):
games.setdefault(game_no, {}).setdefault(player_name, {})
games[game_no][player_name] = score
# the dictionary "games" will look like:
# {1: {'Anna': 95, 'Bob': 90, 'Joe': 100, 'May': 80},
# 2: {'Anna': 32, 'Bob': 38, 'Joe': 34, 'May': 36},
# 3: {'Anna': 36, 'Bob': 4, 'Joe': 38, 'May': 40},
# 4: {'Anna': 92, 'Bob': 100, 'Joe': 90, 'May': 91},
# 5: {'Anna': 68, 'Bob': 60, 'Joe': 67, 'May': 70},
# 6: {'Anna': 8, 'Bob': 4, 'Joe': 3, 'May': 2},
# 7: {'Anna': 13, 'Bob': 11, 'Joe': 10, 'May': 12}}
Now I'm trying out different ways to rank each player's score of each game and then add up those scores to return something like this:
{'Anna': 23, 'May': 18, 'Bob': 16, 'Joe': 15}
The score above is generated when the sum of the ranking of each game is returned. I let the best player, with the highest score of each game earn 4 points, the second one 3, etc.
Of course, it isn't very hard to just sort the outcomes of game 1 like this:
score_list = []
for p in players_score:
score_list.append(p[1])
score_list.sort(reverse=True)
print(score_list)
Returns: [100, 95, 90, 80]
Would it be any good to search in the list/dictionary for these values a then add the points (4/3/2/1) to the name and finally sum them up?
Try this :
from itertools import zip_longest as zilo
tt = list(sorted(i, reverse=True) for i in zilo(*[v for _, *v in players_score]))
# tt = [[100, 95, 90, 80], [38, 36, 34, 32], [40, 38, 36, 4], [100, 92, 91, 90], [70, 68, 67, 60], [8, 4, 3, 2], [13, 12, 11, 10]]
score_dict = {k : sum(4-j.index(i) for i,j in zip(v, tt)) for k, *v in players_score}
Output :
{'Joe': 15, 'Bob': 17, 'May': 18, 'Anna': 20}
Explanation :
First of all, we get the scores of each players for a game in a tuple with zip_longest from itertools with this :
zipped = list(zilo(*[v for _, *v in players_score]))
Now, zipped is :
[(100, 90, 80, 95), (34, 38, 36, 32), (38, 4, 40, 36), (90, 100, 91, 92), (67, 60, 70, 68), (3, 4, 2, 8), (10, 11, 12, 13)]
Check first item (tuple) is the score of four players for the first game and so on. Now we sort each tuple, in the descending order to this :
tt = list(sorted(i, reverse=True) for i in zipped)
So, tt now becomes :
[[100, 95, 90, 80], [38, 36, 34, 32], [40, 38, 36, 4], [100, 92, 91, 90], [70, 68, 67, 60], [8, 4, 3, 2], [13, 12, 11, 10]]
Now, we need to assign scores for each player. We can break down the one-liner dict-comprehension like this :
score_dict = {}
for k, *v in players_score:
tmp = []
for i,j in zip(v, tt):
tmp.append(4-j.index(i)) #Change your score assigning logic here [5,3,1,0] in stead of [4,3,2,1]
#print(tmp) #Check here for scores in each game for a player
tot_score = sum(tmp)
score_dict[k] = tot_score
#print(score_dict)
We iterate over the players_score, we take the first item of each tuple k in it as player name, the rest as another tuple v (the scores of one player in all games), we then zip this tuple v and previous tt, to assign values for rank in each particular game. Scores assigned are 4-the_sorted_one_game_scores_tuple.index(particular_players_score_in_that_game) and all these scores are being appended to a temporary list for each players. After we get the scores for all the games, we sum them up and assign this summation value tot_score as the value to the key k for the score_dict dictionary.
Update :
You can use 5-2*j.index(i) if 5-2*j.index(i) > 0 else 0 in place of 4-j.index(i). Please note that for that case you must have less than 5 games as more than 5 games would assign the last guy and the second last guy both zero. If you want to generalize this logic to assign 0,1,3,5,7,9,... for more number of persons; then you have use a function 2*x-1 if 2*x-1 > 0 else 0 to generate this number sequence. in that case, change inside the second for loop, where we are appending the scores in a temporary list, like this :
# To get 0,1,3,5,7,9,... type score
score_func = lambda x: 2*x-1 if 2*x-1>0 else 0
score_dict = {}
for k, *v in players_score:
tmp = []
for i,j in zip(v, tt):
tmp.append(score_func(j.index(i)))
tot_score = sum(tmp)
score_dict[k] = tot_score
print(score_dict)
I am trying to test the function map with the method append and got a wrong output.
Code
numbers = [
[34, 63, 88, 71, 29],
[90, 78, 51, 27, 45],
[63, 37, 85, 46, 22],
[51, 22, 34, 11, 18]
]
numbers_tmp = []
def mean_append(num_list):
numbers_tmp.append(sum(num_list) / len(num_list))
return numbers_tmp
print(list(map(mean_append, numbers)))
Expected output
[57.0, 58.2, 50.6, 27.2]
Actual output
[
[57.0, 58.2, 50.6, 27.2],
[57.0, 58.2, 50.6, 27.2],
[57.0, 58.2, 50.6, 27.2],
[57.0, 58.2, 50.6, 27.2]
]
Built-in map works on each value in an iterable. So your function should include logic which can be applied to each sublist:
def mean_calculator(num_list):
return sum(num_list) / len(num_list)
res = list(map(mean_calculator, numbers))
print(res)
[57.0, 58.2, 50.6, 27.2]
Alternatively, you can use statistics.mean from the standard library:
from statistics import mean
res = list(map(mean, numbers))
map returns one output object for each object in the input sequence. Your input sequence has 4 objects, so the output has 4 objects. They're all same since your function always returns same numbers_tmp object. To fix the problem stop using global variables in map.
numbers = [[34, 63, 88, 71, 29], [90, 78, 51, 27, 45], [63, 37, 85, 46, 22], [51, 22, 34, 11, 18]]
def mean_append(num_list):
return sum(num_list) / len(num_list)
print(list(map(mean_append, numbers)))
I am trying to write a function named studentGrades(gradeList) that takes a nested list and returns a list with the average score for each student.
An example would be:
grades= [['Student','Quiz 1','Quiz 2','Quiz 3','Final'],
['John', 100, 90, 80, 90],
['McVay', 88, 99, 11, 15],
['Rita', 45, 56, 67, 89],
['Ketan', 59, 61, 67, 32],
['Saranya', 73, 79, 83, 45],
['Min', 89, 97, 101, 100]]
studentGrades(grades)
# Sample output below
>>> [90, 53, 64, 54, 70, 96]
I don't know how to do this using a nested loop. Any help or guidance is appreciated.
Incase you need a one liner
[int(sum(i[1:])/len(i[1:])) for i in grades[1:]]
Output:
[90, 53, 64, 54, 70, 96]
As I suggested in the comments, you can also use a dictionary for that. Dictionaries are basically made for situations like these and if you want to use your data any further, they might prove beneficial.
You would first have to convert your current structure, which I assumed is fixed in the sense that you have a "header" in grades, and then lists of the form [name,points..]. You can do:
grades= [['Student','Quiz 1','Quiz 2','Quiz 3','Final'],
['John', 100, 90, 80, 90],
['McVay', 88, 99, 11, 15],
['Rita', 45, 56, 67, 89],
['Ketan', 59, 61, 67, 32],
['Saranya', 73, 79, 83, 45],
['Min', 89, 97, 101, 100]]
gradedict = {}
for rows in grades[1:]:
gradedict[rows[0]] = rows[1:]
To initialize the dictionary. Then the following function:
def studentGrades(gradedict):
avgdict = {}
for key,lst in gradedict.items():
avgdict[key] = sum(lst)/len(lst)
return avgdict
Returns another dictionary with the corresponding averages. You could loop through the names, i.e. the keys, of either of those to print that. For example:
gradedict = studentGrades(gradedict)
for x in gradedict:
print("student ",x, " achieved an average of: ",gradedict[x])
which is just to show you how to access the elements. you can of course also loop through keys,items as I did in the function.
Hope this helps.
You can do something like this:
def studentGrades(a):
# return [sum(k[1:])/(len(k)-1) for k in a[1:]]
# Or
l = len(a[0]) - 1 # how many quizzes, thanks to #Mad Physicist
return [sum(k[1:])/l for k in a[1:]]
grades= [['Student','Quiz 1','Quiz 2','Quiz 3','Final'],
['John', 100, 90, 80, 90],
['McVay', 88, 99, 11, 15],
['Rita', 45, 56, 67, 89],
['Ketan', 59, 61, 67, 32],
['Saranya', 73, 79, 83, 45],
['Min', 89, 97, 101, 100]]
final = studentGrades(grades)
print(final)
Output:
[90, 53, 64, 54, 70, 96]
Why not just use pandas?
df = pd.DataFrame(grades).set_index(0).iloc[1:].mean(axis=1).astype(int)
Output:
John 90
McVay 53
Rita 64
Ketan 54
Saranya 70
Min 96
or
list(df.values)
Output:
[90, 53, 64, 54, 70, 96]
grades= [['Student','Quiz 1','Quiz 2','Quiz 3','Final'],
['John', 100, 90, 80, 90],
['McVay', 88, 99, 11, 15],
['Rita', 45, 56, 67, 89],
['Ketan', 59, 61, 67, 32],
['Saranya', 73, 79, 83, 45],
['Min', 89, 97, 101, 100]]
def average(grades):
for m in grades[1:]:
t = m[1:]
l = len(t)
s = sum(t)
yield s//l
list(average(grades))
So, for fun and practice I have been following along a college friend and their more advanced programming class and tackling assignments they are assigned to ready myself for the same Python class. I'm now at dictionaries and tuples sorting them based on the least to greatest number in an assigned dictonary. so far I have this code:
cityRevenues = {'Alabaster':[40,50,23,18], 'Anniston':[56,78,34,11],
'Athens':[40,34,18,30],'Auburn':[55,67,23,11],
'Decatur':[44,23,56,11],'Florence':[55,67,33,23],'Gadsden':[45,67,54,77]}
a = (sorted(cityRevenues.items(), key=lambda x: x[1]))
print('Sort the cities by their Quarter 1 Revenues.')
print("")
print(a)
print("")
b = (sorted(cityRevenues.items(), key=lambda x: x[1][1]))
print('Sort the cities by their Quarter 2 Revenues.')
print("")
print(b)
print("")
c = (sorted(cityRevenues.items(), key=lambda x: x[1][2]))
print("Sort the cities by their Quarter 3 Revenues.")
print("")
print(c)
print("")
d = (sorted(cityRevenues.items(), key=lambda x: x[1][3]))
print("Sort the cities by their Quarter 4 Revenues.")
print("")
print(d)
print("")
which gives the output:
Sort the cities by their Quarter 1 Revenues.
[('Athens', [40, 34, 18, 30]), ('Alabaster', [40, 50, 23, 18]), ('Decatur', [44, 23, 56, 11]), ('Gadsden', [45, 67, 54, 77]), ('Auburn', [55, 67, 23, 11]), ('Florence', [55, 67, 33, 23]), ('Anniston', [56, 78, 34, 11])]
Sort the cities by their Quarter 2 Revenues.
[('Decatur', [44, 23, 56, 11]), ('Athens', [40, 34, 18, 30]), ('Alabaster', [40, 50, 23, 18]), ('Auburn', [55, 67, 23, 11]), ('Florence', [55, 67, 33, 23]), ('Gadsden', [45, 67, 54, 77]), ('Anniston', [56, 78, 34, 11])]
Sort the cities by their Quarter 3 Revenues.
[('Athens', [40, 34, 18, 30]), ('Auburn', [55, 67, 23, 11]), ('Alabaster', [40, 50, 23, 18]), ('Florence', [55, 67, 33, 23]), ('Anniston', [56, 78, 34, 11]), ('Gadsden', [45, 67, 54, 77]), ('Decatur', [44, 23, 56, 11])]
Sort the cities by their Quarter 4 Revenues.
[('Auburn', [55, 67, 23, 11]), ('Decatur', [44, 23, 56, 11]), ('Anniston', [56, 78, 34, 11]), ('Alabaster', [40, 50, 23, 18]), ('Florence', [55, 67, 33, 23]), ('Athens', [40, 34, 18, 30]), ('Gadsden', [45, 67, 54, 77])]
I managed to sort them based on the least to greatest in each tuple, but I do not know how to code it to where it shows only the one value that is greatest in the tuple. i.e.:
Sort the cities by their Quarter 1 Revenues.
[('Athens', [40]), ('Alabaster', [40]), ('Decatur', [44]), ('Gadsden', [45]), ('Auburn', [55]), ('Florence', [55]), ('Anniston', [56])]
How would I go about having the specific tuple values be the only ones printed?
Try the following:
# To get the first value of the list for the city, use pair[1][0].
# You can get the second value of the list for the city by using pair[1][1]
# An so on...
>>> d = {pair[0]: [pair[1][0]] for pair in sorted(cityRevenues.items(), key=lambda x: x[1][3])}
>>> list(d.items())
[('Gadsden', [45]), ('Athens', [40]), ('Anniston', [56]), ('Alabaster', [40]), ('Florence', [55]), ('Auburn', [55]), ('Decatur', [44])]
Since the largest element is at the end of the list, you can use index -1
e.g.
cityRevenues = {'Alabaster':[40,50,23,18], 'Anniston':[56,78,34,11],
'Athens':[40,34,18,30],'Auburn':[55,67,23,11],
'Decatur':[44,23,56,11],'Florence':[55,67,33,23],'Gadsden':[45,67,54,77]}
a = (sorted(cityRevenues.items(), key=lambda x: x[1]))
print('Sort the cities by their Quarter 1 Revenues.')
print("\n")
print(a[-1])
print("\n")
It will give
('Anniston', [56, 78, 34, 11])
You print the last item in the list:
print (a[-1])
Format as desired.
By the way, you can make this code much shorter if you use the same variable name for each sorted list, and also collect your keys in a list you can index according to the input choice.