Deriving len/min/sum of dictionary values - python

I have the following dictionary for which I’d like to produce a new dictionary that gives the original keys but the values are computed using len, min and sum.
scores = {
"Monday" : [21, 23, 24, 19],
"Tuesday" : [16, 15, 12, 19],
"Wednesday" : [23, 22, 23],
"Thursday": [ 18, 20, 26, 24],
"Friday": [17, 22],
"Saturday" : [22, 24],
"Sunday" : [21, 21, 28, 25]
}
I initially tried to use the following but it only returns a single value:
for k, v in scores.items():
stat = {
k : [len(v), min(v), sum(v)]
}
This returns: {'Sunday': [4, 21, 95]}
Doing some research, I managed to use the following comprehension to achieve the outcome:
stats = {k : [len(v), min(v), sum(v)] for k, v in scores.items()}
This returns:
{'Monday': [4, 19, 87], 'Tuesday': [4, 12, 62], 'Wednesday': [3, 22, 68], 'Thursday': [4, 18, 88], 'Friday': [2, 17, 39], 'Saturday': [2, 22, 46], 'Sunday': [4, 21, 95]}
I would really like to understand why my first attempt only produced a single value and didn’t iterate through the entire dictionary?
I’m new to learning Python so very keen to understand the difference in methods and what I was doing incorrect with the first method.
Many thanks!
JJ

This code:
for k, v in scores.items():
stat = {
k : [len(v), min(v), sum(v)]
}
is the equivalent of doing:
stat = {"Monday" : [len(scores["Monday"]), min(scores["Monday"]), sum(scores["Monday"])}
stat = {"Tuesday" : [len(scores["Tuesday"]), min(scores["Tuesday"]), sum(scores["Tuesday"])}
...
stat = {"Sunday" : [len(scores["Sunday"]), min(scores["Sunday"]), sum(scores["Sunday"])}
On each iteration of the loop, you're re-assigning stat to a new single-item dictionary. The last one is Sunday, so that's the final value that stat has after the loop is finished.
If you did something like:
stat = {}
for k, v in scores.items():
stat[k] = [len(v), min(v), sum(v)]
your end result would be an accumulation of all the values, similar to the result you get from the dictionary comprehension (which is generally the preferred way of building a dictionary through iteration).

your script is iterating arround all dictionary
but you are overriting the result dictionary
try something like:
stats = []
for k, v in scores.items():
stat = {
k : [len(v), min(v), sum(v)]
}
stats.append(stat)
print(stats)

Related

Get dictionary from a dataframe

I have a dataframe like below:
df = pd.DataFrame({
'Aapl': [12, 5, 8],
'Fs': [18, 12, 8],
'Bmw': [6, 18, 12],
'Year': ['2020', '2025', '2030']
})
I want a dictionary like:
d={'2020':[12,18,16],
'2025':[5,12,18],
'2030':[8,8,12]
}
I am not able to develop the whole logic:
lst = [list(item.values()) for item in df.to_dict().values()]
dic={}
for items in lst:
for i in items[-1]:
dic[i]=#2000 will hold all the 0th values of other lists and so on
Is there any easier way using pandas ?
Convert Year to index, transpose and then in dict comprehension create lists:
d = {k: list(v) for k, v in df.set_index('Year').T.items()}
print (d)
{'2020': [12, 18, 6], '2025': [5, 12, 18], '2030': [8, 8, 12]}
Or use DataFrame.agg:
d = df.set_index('Year').agg(list, axis=1).to_dict()
print (d)
{'2020': [12, 18, 6], '2025': [5, 12, 18], '2030': [8, 8, 12]}
Try this:
import pandas as pd
data = {'Name': ['Ankit', 'Amit',
'Aishwarya', 'Priyanka'],
'Age': [21, 19, 20, 18],
'Stream': ['Math', 'Commerce',
'Arts', 'Biology'],
'Percentage': [88, 92, 95, 70]}
# Convert the dictionary into DataFrame
df = pd.DataFrame(data, columns=['Name', 'Age',
'Stream', 'Percentage'])

Python fetch all consecutive odd or even numbers

Given a list of integers, how can I group together consecutive numbers that share the same parity?
Here is an example input:
[5, 9, 11, 20, 24, 30, 31, 33, 39, 41]
And here is an example output:
[[5, 9, 11], [20, 24, 30], [31, 33, 39, 41]]
a simple loop does the job:
test = [5,7,9,11,13,20,22,24,31,33,39,41,43,44,46,50,52]
result = []
res = []
prevalue = None
for v in test:
if prevalue == None or v == prevalue + 2:
prevalue = v
res.append(v)
else:
prevalue = v
result+= [res]
res = [v]
result+= [res]
print(result)
result:
[[5, 7, 9, 11, 13], [20, 22, 24], [31, 33], [39, 41, 43], [44, 46], [50, 52]]
You can use itertools.groupby() to produce the groupings of odd / even numbers:
[list(group) for _, group in groupby(data, lambda x: x % 2 == 0)]
This outputs:
[[5, 9, 11], [20, 24, 30], [31, 33, 39, 41]]
Basically, what you want to do is track the current list you're looking at and modify it as you go and, when your condition no longer holds true, you save the list and create a new one:
results = []
current = [data[0]]
flag = data[0] % 2
for number in data[1:]:
if number % 2 == flag:
current.append(number)
else:
flag = 1 - flag
results.append(current)
current = [number]
results.append(current)

Given a dictionary of lists, is there a pythonic smart way of comparing the i-th element of each list and extract the maximum value?

I have a dictionary like the following:
{
'k0': [10, 35, 20],
'k1': [2, 0, 40],
'k2': [21, 400, 5],
}
I want to obtain a list with the maximum values in each i-th position of the list. For instance, in this case:
max_val_list = [21, 400, 40]
Current way of doing it (which seems too messy to me):
1. Extract the lists:
k0_list = dicc_name[k0]
k1_list = dicc_name[k1]
k2_list = dicc_name[k2]
Find the max:
for i, item in enumerate(k0_list):
max_val_list.append(max([item, k1_list[i], k2_list[i]]))
I am sure there must be a way to do it in an elegant way directly from the dictionary and I would like to learn.
You can zip the values of the dict, and get the max of each column:
data = {
'k0': [100, 35, 20],
'k1': [2, 0, 40],
'k2': [21, 400, 5],
}
[max(col) for col in zip(*data.values())]
# [100, 400, 40]
If you use numpy
>>> import numpy as np
>>> np.max([*data.values()],axis = 0).tolist()
[100, 400, 40]

Merge two list contained dictionary based on its index in python

I have two list contain multi dictionary, each dictionary has a list as value, these are my list:
list1 = [{'a':[12,22,61],'b':[21,12,50]},{'c':[10,11,47],'d':[13,20,45],'e':[11,24,42]},{'a':[12,22,61],'b':[21,12,50]}]
list2 = [{'f':[21,23,51],'g':[11,12,44]},{'h':[22,26,68],'i':[12,9,65],'j':[10,12,50]},{'f':[21,23,51],'g':[11,12,44]}]
In my case, i need to merge these list with this rule:
Dictionary from the first list (list1) only can be merged by
dictionary from the second list (list2) with the same listing index
After both of these list are merged, each dictionary has to be sorted based on the third number of its value
This is the expected result based on two rule above:
result = [
{'a':[12,22,61],'f':[21,23,51],'b':[21,12,50],'g':[11,12,44]},
{'h':[22,26,68],'i':[12,9,65],'j':[10,12,50],'c':[10,11,47],'d':[13,20,45],'e':[11,24,42]},
{'a':[12,22,61],'f':[21,23,51],'b':[21,12,50],'g':[11,12,44]}
]
How can i do that? is it possible to be done in python with inline looping?
Try:
[dict(a, **b) for a,b in zip(list1, list2)]
In one line (if you do not count with the import):
from collections import OrderedDict
[OrderedDict(sorted(dict(d1.items() + d2.items()).items(), key=lambda x: x[1][-1],
reverse=True)) for d1, d2 in zip(list1, list2)]
[OrderedDict([('a', [12, 22, 61]),
('f', [21, 23, 51]),
('b', [21, 12, 50]),
('g', [11, 12, 44])]),
OrderedDict([('h', [22, 26, 68]),
('i', [12, 9, 65]),
('j', [10, 12, 50]),
('c', [10, 11, 47]),
('d', [13, 20, 45]),
('e', [11, 24, 42])]),
OrderedDict([('a', [12, 22, 61]),
('f', [21, 23, 51]),
('b', [21, 12, 50]),
('g', [11, 12, 44])])]
This works in Python 2.7.
Dictionaries are not sorted by nature, so if you don't need them sorted your can merge them in a simple one-liner.
result = [ {**d1, **d2} for d1, d2 in zip(list1, list2) ] # python 3.5+
If you are using a lower version then define a merge function.
def merge(d1, d2):
result = d1.copy()
result.update(d2)
return result
And then have
result = [ merge(d1, d2) for d1, d2 in zip(list1, list2) ]
If you do need them sorted then your only option is to use an OrderedDict
from collections import OrderedDict
def merge(d1, d2):
tempD = d1.copy()
tempD.update(d2)
return OrderedDict(sorted(tempD.items(), key = lambda t: t[1][2], reverse = True))
result = [ merge(d1, d2) for d1, d2 in zip(list1, list2) ]
Or even shorter for python 3.5+ is
result = [ OrderedDict(sorted(({**d1, **d2}).items(), key = lambda t: t[1][2], reverse = True)) for d1, d2 in zip(list1, list2) ]
You can do like this for your result :
r = map(lambda x,y:dict(x.items() + y.items()), list1, list2)
Result :
[{'a': [12, 22, 61], 'b': [21, 12, 50], 'g': [11, 12, 44], 'f': [21, 23, 51]},
{'c': [10, 11, 47], 'e': [11, 24, 42], 'd': [13, 20, 45], 'i': [12, 9, 65], 'h': [22, 26, 68], 'j': [10, 12, 50]},
{'a': [12, 22, 61], 'b': [21, 12, 50], 'g': [11, 12, 44], 'f': [21, 23, 51]}]

Dictionary with Keys inside Keys

I need to find a way to return the 1st value inside the key 'hw' for keys 1 and 2 and sum them but I cannot think of a way.It needs to work for any number of keys, not just 1 and 2 but even if there were 10 or so. The 1 and 2 are the students, the 'hw','qz',,etc are the categories of assignments,every student will have hw,qz,ex,pr and there will be 3 qz,3hw,3pr,3ex for each student. I need to return all the students 1st, hw grade, 1st quiz grade, 2nd hw grade..etc
grades = {
1: {
'pr': [18, 15],
'hw': [16, 27, 25],
'qz': [8, 10, 5],
'ex': [83, 93],
},
2: {
'pr': [20, 18],
'hw': [17, 23, 28],
'qz': [9, 9, 8],
'ex': [84, 98],
},
}
More succinctly (and Pythonicly):
hw_sum = sum([grades[key]['hw'][0] for key in grades])
return the 1st value inside the key 'hw' for keys 1 and 2 and sum them
It helps to use explanatory names so we know what the moving parts are meant to be. I've chosen descriptive names somewhat arbitrarily by guessing at the meaning.
Succinct solution
grades_by_year_and_subject = {
1: {
'pr': [18, 15],
'hw': [16, 27, 25],
'qz': [8, 10, 5],
'ex': [83, 93],
},
2: {
'pr': [20, 18],
'hw': [17, 23, 28],
'qz': [9, 9, 8],
'ex': [84, 98],
},
}
sum_of_grades_for_year_1_and_2_for_subject_hw = sum(
grades[0] for grades in (
grades_by_subject['hw']
for (year, grades_by_subject) in
grades_by_year_and_subject.items()
if year in [1, 2]
)
)
Breaking this into several smaller problems:
Sum a collection of values
sum_of_grades = sum(values)
Get the set of first values from a collection of lists
set_of_first_grades = {
values[0] for values in collection}
Make a generator of the values for key 'hw' in each dict from a collection
generator_of_hw_value_lists = (
values_dict['hw'] for values_dict in
collection_of_dicts.values())
Reduce a dictionary only to those items with keys 1 or 2
mapping_of_values_for_key_1_and_2 = {
key: value
for (key, value) in values_dict.items()
if key in [1, 2]}
Verbose solution
grades_by_year_and_subject = {
1: {
'pr': [18, 15],
'hw': [16, 27, 25],
'qz': [8, 10, 5],
'ex': [83, 93],
},
2: {
'pr': [20, 18],
'hw': [17, 23, 28],
'qz': [9, 9, 8],
'ex': [84, 98],
},
}
grades_for_year_1_and_2_by_subject = {
year: grades_by_subject
for (year, grades_by_subject) in
grades_by_year_and_subject.items()
if year in [1, 2]}
grades_for_year_1_and_2_for_subject_hw = (
grades_by_subject['hw']
for grades_by_subject in
grades_for_year_1_and_2_by_subject.values())
sum_of_grades_for_year_1_and_2_for_subject_hw = sum(
grades[0] for grades in grades_for_year_1_and_2_for_subject_hw)

Categories