How to make and average of all ages in dictionary? [duplicate] - python

This question already has answers here:
Get average value from list of dictionary
(4 answers)
Closed 7 months ago.
I am new to python and I am trying to count the number of males and females in a list and that worked but I do not know how to make the average of all the ages in the list.
user_list = [
{'name': 'Alizom_12',
'gender': 'f',
'age': 34,
'active_day': 170},
{'name': 'Xzt4f',
'gender': None,
'age': None,
'active_day': 1152},
{'name': 'TomZ',
'gender': 'm',
'age': 24,
'active_day': 15},
{'name': 'Zxd975',
'gender': None,
'age': 44,
'active_day': 752},
]
def user_stat():
from collections import Counter
counts = Counter((user['gender'] for user in user_list))
print(counts)
user_stat()

def user_stat():
# Here we get rid of the None elements
user_list_filtered = list(filter(lambda x: isinstance(x['age'], int), user_list))
# Here we sum the ages and divide them by the amount of "not-None" elements
print(sum(i.get('age', 0) for i in user_list_filtered) / len(user_list_filtered))
# If you want to divide by None-elements included
print(sum(i.get('age', 0) for i in user_list_filtered) / len(user_list))
user_stat()

not entirely sure if this is what you are looking for, but maybe try with two dicts:
cont = {'m': 0, 'f': 0}
avgs = {'m': 0, 'f': 0}
for u in user_list:
gdr = u['gender']
if not gdr:
continue
cont[gdr] += 1
avgs[gdr] += u['age']
for g in avgs:
avgs[g] /= cont[g]
print(avgs) # {'m': 24.0, 'f': 34.0}

you can try something like this. As you can also have None for the age. Try using .get method for a dict.
total_age = 0
for user in user_list:
if user.get('age'):
total_age = total+user['age']
avg_age = total_age/len(user_list)
Hope it helps!!

If you have trouble understanding lambda, this can be another option.
user_list = [
{'name': 'Alizom_12',
'gender': 'f',
'age': 34,
'active_day': 170},
{'name': 'Xzt4f',
'gender': None,
'age': None,
'active_day': 1152},
{'name': 'TomZ',
'gender': 'm',
'age': 24,
'active_day': 15},
{'name': 'Zxd975',
'gender': None,
'age': 44,
'active_day': 752},
]
ages = []
def user_stat():
for age in user_list:
if isinstance(age["age"], int):
ages.append(age["age"]) # If the age is an integer, add it to a list.
average = sum(ages) / len(ages) # Creates average by dividing the sum with the length of the list
print(f"The age average is {average}")
user_stat()

you can try something like:
ages = [user['age'] for user in user_list if user['gender'] == 'f']
avg = sum(ages) / len(ages)

Related

How to count the number of similar values in a dictionary?

Is there a way to count the number of similar values in a dictionary,for example I have a list consisting of different users and their names, gender, age ... if I want to count the number of males in that list how to do it?
I know it might sound silly but I am new to python and I am trying to learn more about it.
This is the list if it will help:
user_list = [
{'name': 'Alizom_12',
'gender': 'f',
'age': 34,
'active_day': 170},
{'name': 'Xzt4f',
'gender': None,
'age': None,
'active_day': 1152},
{'name': 'TomZ',
'gender': 'm',
'age': 24,
'active_day': 15},
{'name': 'Zxd975',
'gender': None,
'age': 44,
'active_day': 752},
]
Here are two solutions for your example of counting genders:
n_males = sum(1 for user in user_list if user['gender'] == 'm')
print(n_males )
Use the counter
from collections import Counter
counts = Counter((user['gender'] for user in user_list))
print(counts)
You can create a function like:
def count_gender(lst, gender):
count=0
for dictionary in lst:
if dictionary["gender"] == gender:
count+=1
return count
Then pass into it list and desired gender:
number = count_gender(user_list, "m")
print(number)
You can use the sum function.
user_list = [
{'name': 'Alizom_12',
'gender': 'f',
'age': 34,
'active_day': 170},
{'name': 'Xzt4f',
'gender': None,
'age': None,
'active_day': 1152},
{'name': 'TomZ',
'gender': 'm',
'age': 24,
'active_day': 15},
{'name': 'Zxd975',
'gender': None,
'age': 44,
'active_day': 752},
]
print(sum(user["gender"] == "m" for user in user_list))
I gave a list comprehension in parameter to filter the users with the attribute gender set to m. You can easily create a function to make the operation more efficient.
def count_by_attribute(my_list: List, attribute: str, value: Any) -> int:
return sum(o[attribute] == value for o in my_list)
n = len([i.gender for i in user_list if i.gender == "m"])
Here you're calculating the len of the list generated by this sintax called list comprehension, that takes all the i.gender of all the values in your dictionary, where the gender is "m"
that should do the trick
print(sum(x.get('gender') == 'm' for x in user_list))
the .get function Returns the value for key if key is in the dictionary, else default. so we just count the values m and get 1 in your example case.

Convert a list and list of tuples to dictionary

I have a list of tuples
data = [('2015-10-08', '2016-07-17'), ('Alex', 'Jerry'), (5, 6)]
And I have a list, this list contains column headings.
title = [Date , Name, Age]
With this list and list of tuples I want a dictionary of dictionaries
This is the expected output
output = {'1' : {'Date': '2015-10-08', 'Name': 'Alex', 'Age': 5},
'2' : {'Date': '2016-07-17', 'Name': 'Jerry', 'Age': 6}}
I tried
output = {}
for i in range(len(title)):
output[i+1] = {title[i]: ",".join(data[i])}
print (output)
I am getting
{1: {'Date': '2015-10-08','2016-07-17'}, 2: {'Name': 'Alex','Jerry'}, 3: {'Age': 5,6}}
You could simply use loops to build easy to read code. But the Pythonic way would be to use comprehensions:
result = {str(i + 1): {t: data[j][i] for j, t in enumerate(title)}
for i in range(len(data[0]))}
It gives as expected:
{'1': {'Age': 5, 'Date': '2015-10-08', 'Name': 'Alex'},
'2': {'Age': 6, 'Date': '2016-07-17', 'Name': 'Jerry'}}

How to make a list of dicts from a list of values for a fixed set of keys

I have a list like this:
list = ['John', 18, 'Spain', 'Adam', 12, 'Hungary', 'Eve', 50, 'Greece', ...]
How can I make a list of dictionaries from it?
The expected result:
[{'name':'John', 'age':18, 'country':'Spain'},
{'name':'Adam', 'age':12, 'country':'Hungary'},
{'name':'Eve', 'age':50, 'country':'Greece'},
...]
You could use zip with different slicing of your values
values[::3] iterates 1 over 3, so only names
values[1::3] iterates 1 over 3 starting at index 1, so only ages
values[2::3] iterates 1 over 3 starting at index 2, so only countries
values = ['John', 18, 'Spain', 'Adam', 12, 'Hungary', 'Eve', 50, 'Greece']
list2 = []
for name, age, country in zip(values[::3], values[1::3], values[2::3]):
list2.append({'name': name, 'age': age, 'country': country})
print(list2)
You can also use dict+zip to build the dict with keys+values
list2 = [
dict(zip(['name', 'age', 'country'], vals))
for vals in zip(values[::3], values[1::3], values[2::3])
]
You need to loop over the list in groups of 3 elements, and append one dictionary each time, not three separate dictionaries.
for i in range(0, len(list), 3):
list2.append({
'name': list[i],
'age': list[i+1],
'country': list[i+2]
})
Also, you shouldn't use list as a variable name, it conflicts with the built-in function with that name.
If you know zip() and that it loops over iterators in parallel, it is interesting to know that it can loop over on a single iterator in parallel, practically slicing the input into tuples:
lista = ['John', 18, 'Spain', 'Adam', 12, 'Hungary', 'Eve', 50, 'Greece']
it = iter(lista)
[adat for adat in zip(it,it,it)]
produces
[('John', 18, 'Spain'), ('Adam', 12, 'Hungary'), ('Eve', 50, 'Greece')]
and then for the dicts you can either index the elements as adat[0], etc. or have Python to assign them to a tuple of variables:
lista = ['John', 18, 'Spain', 'Adam', 12, 'Hungary', 'Eve', 50, 'Greece']
it = iter(lista)
[{'name':name,'age':age,'country':country} for (name,age,country) in zip(it,it,it)]
will display
[{'name': 'John', 'age': 18, 'country': 'Spain'}, {'name': 'Adam', 'age': 12, 'country': 'Hungary'}, {'name': 'Eve', 'age': 50, 'country': 'Greece'}]
Side note: list() is a built-in function, so I renamed the variable to lista, based on adat :-)
(Side note2: zip() consumes the iterator, so it has to be re-created if you try both of these snippets together)
Simple, readable way:
lst = ['John', 18, 'Spain', 'Adam', 12, 'Hungary', 'Eve', 50, 'Greece']
ans = []
for i in range(0,len(lst),3):
ans.append({'name':lst[i], 'age':lst[i+1], 'country':lst[i+2]})
print(ans) #prints [{'name': 'John', 'age': 18, 'country': 'Spain'}, {'name': 'Adam', 'age': 12, 'country': 'Hungary'}, {'name': 'Eve', 'age': 50, 'country': 'Greece'}]
A quick and dirty way to do it is like this:
list_1 = ['John', 18, 'Spain', 'Adam', 12, 'Hungary', 'Eve', 50, 'Greece']
list_2 = []
for i in range(0, len(list_1), 3):
list_2.append({'name': list_1[i], 'age': list_1[i + 1], 'country': list_1[i + 2]})
here is my take on the problem
list_ = ['John', 18, 'Spain', 'Adam', 12, 'Hungary', 'Eve', 50, 'Greece']
result = []
for index, item in enumerate(list_):
try:
int(item)
dictionary = dict()
dictionary['name'] = list_[index - 1]
dictionary['age'] = item
dictionary['country'] = list_[index + 1]
result.append(dictionary)
except ValueError:
pass
print(result)
its pretty simple enumerate gives another variable which is list index, then I try to make item in list integer and that wont happen with those strings so it will throw ValueError and pass and continue untile it finds an int then it will create a dictionary and add neccessary items to the it and then add the dictionary to the list (also do not use list as variable because its python reserved? keyword?)
You can loop over the list over every three steps. An example to help get you started is:
>>> for i in range(0, 12, 3): # 0 = start value, 12 = stop value, 3 = step
... print(i)
...
0
3
6
9
>>>
Similarly you can do:
data_list = ['John', 18, 'Spain', 'Adam', 12, 'Hungary', 'Eve', 50, 'Greece'...]
data_dicts = []
for i in range(0, len(data_list), 3):
data_dicts.append(
{'name': data_list[i], # The first element in a group of 3 (the name)
'age': data_list[i + 1], # The second element in the group (the age)
'country': data_list[i + 2] # The last element in the group (the country)
}
)
Also, you shouldn't name any variable list because it will override the built in python list class

Find a value in a list of dicts [duplicate]

This question already has answers here:
Get the first item from an iterable that matches a condition
(18 answers)
Closed 4 years ago.
Let:
M = [{'name': 'john', 'result': 12},
{'name': 'sara', 'result': 20},
{'name': 'karl', 'result': 11}]
If I want to find Sara's result, I thought about:
M[[m['name'] for m in M].index('sara')]['result'] # hard to read, but works
and
[m['result'] for m in M if m['name'] == 'sara'][0] # better
Is there an even more natural way to do this in Python?
Use a generator with next().
next(m['result'] for m in L if m['name'] == 'sara')
If you have several lookups to perform, linear search isn't the best option.
Rebuild a dictionary once with the proper key (name):
M = [{'name': 'john', 'result': 12},
{'name': 'sara', 'result': 20},
{'name': 'karl', 'result': 11}]
newdict = {d["name"] : d["result"] for d in M}
It creates:
{'john': 12, 'karl': 11, 'sara': 20}
now when you need the result from a name, just do:
print(newdict.get('sara'))

Efficiently sum items by type

I have a list of items with properties "Type" and "Time" that I want to quickly sum the time for each "Type" and append to another list. The list looks like this:
Items = [{'Name': A, 'Type': 'Run', 'Time': 5},
{'Name': B, 'Type': 'Walk', 'Time': 15},
{'Name': C, 'Type': 'Drive', 'Time': 2},
{'Name': D, 'Type': 'Walk', 'Time': 17},
{'Name': E, 'Type': 'Run', 'Time': 5}]
I want to do something that works like this:
Travel_Times=[("Time_Running","Time_Walking","Time_Driving")]
Run=0
Walk=0
Drive=0
for I in Items:
if I['Type'] == 'Run':
Run=Run+I['Time']
elif I['Type'] == 'Walk':
Walk=Walk+I['Time']
elif I['Type'] == 'Drive':
Drive=Drive+I['Time']
Travel_Times.append((Run,Walk,Drive))
With Travel_Times finally looking like this:
print(Travel_Times)
[("Time_Running","Time_Walking","Time_Driving")
(10,32,2)]
This seems like something that should be easy to do efficiently with either a list comprehension or something similar to collections.Counter, but I can't figure it out. The best way I have figured is to use a separate list comprehension for each "Type" but that requires iterating through the list repeatedly. I would appreciate any ideas on how to speed it up.
Thanks
Note that case is very important in Python :
For isn't a valid statement
Travel_times isn't the same as Travel_Times
there's no : after elif
Travel_Times.append(... has a leading space, which confuses Python
items has one [ too many
A isn't defined
Having said that, a Counter works just fine for your example :
from collections import Counter
time_counter = Counter()
items = [{'Name': 'A', 'Type': 'Run', 'Time': 5},
{'Name': 'B', 'Type': 'Walk', 'Time': 15},
{'Name': 'C', 'Type': 'Drive', 'Time': 2},
{'Name': 'D', 'Type': 'Walk', 'Time': 17},
{'Name': 'E', 'Type': 'Run', 'Time': 5}]
for item in items:
time_counter[item['Type']] += item['Time']
print(time_counter)
# Counter({'Walk': 32, 'Run': 10, 'Drive': 2})
To get a list of tuples :
[tuple(time_counter.keys()), tuple(time_counter.values())]
# [('Run', 'Drive', 'Walk'), (10, 2, 32)]
You can use a dict to keep track of the total times. Using the .get() method, you can tally up the total times. If the key for the activity doesn't already exist, set its tally to zero and count up from there.
items = [{'Name': 'A', 'Type': 'Run', 'Time': 5},
{'Name': 'B', 'Type': 'Walk', 'Time': 15},
{'Name': 'C', 'Type': 'Drive', 'Time': 2},
{'Name': 'D', 'Type': 'Walk', 'Time': 17},
{'Name': 'E', 'Type': 'Run', 'Time': 5}]
totals = {}
for item in items:
totals[item['Type']] = totals.get(item['Type'], 0) + item['Time']
for k, v in totals.items():
print("Time {}ing:\t {} mins".format(k, v))
You could use Counter from collections along with chain and repeat from itertools:
from itertools import chain, repeat
from collections import Counter
from_it = chain.from_iterable
res = Counter(from_it(repeat(d['Type'], d['Time']) for d in Items))
This small snippet results in a Counter instance containing the sums:
print(res)
Counter({'Drive': 2, 'Run': 10, 'Walk': 32})
It uses repeat to, obviously, repeat the d['Type'] for d['Time'] times and then feeds all these to Counter for the summation using chain.from_iterable.
If your Items list has many entries, you can again use chain.from_iterable to chain these all together:
res = Counter(from_it(repeat(d['Type'], d['Time']) for d in from_it(Items)))
This will get you a sum of all types in all the nested lists.
You can use reduce with collections.Counter:
# from functools import reduce # Python 3
d = reduce(lambda x, y: x + Counter({y['Type']: y['Time']}), Items, Counter())
print(d)
# Counter({'Walk': 32, 'Run': 10, 'Drive': 2})
It simply builds up the Counter updating each Type using the corresponding Time value.
Here is a brief way of expressing what you'd like in one line. By the way, your list Items doesn't need to be double bracketed:
>>> Items = [{'Type': 'Run', 'Name': 'A', 'Time': 5},
{'Type': 'Walk', 'Name': 'B', 'Time': 15},
{'Type': 'Drive', 'Name': 'C', 'Time': 2},
{'Type': 'Walk', 'Name': 'D', 'Time': 17},
{'Type': 'Run', 'Name': 'E', 'Time': 5}]
>>> zip(("Time_Running","Time_Walking","Time_Driving"), (sum(d['Time'] for d in Items if d['Type'] == atype) for atype in 'Run Walk Drive'.split()))
[('Time_Running', 10), ('Time_Walking', 32), ('Time_Driving', 2)]
Here I zipped your output labels to a generator that calculates the sum for each of the three transportation types you have listed. For your exact output you could just use:
>>> [("Time_Running","Time_Walking","Time_Driving"), tuple(sum(d['Time'] for d in Items if d['Type'] == atype) for atype in 'Run Walk Drive'.split())]
[('Time_Running', 'Time_Walking', 'Time_Driving'), (10, 32, 2)]
If you're willing to abuse generators for their side effects:
from collections import Counter
count = Counter()
# throw away the resulting elements, as .update does the work for us
[_ for _ in (count.update({item['Type']:item['Time']}) for item in items) if _]
>>> count
Counter({'Walk': 32, 'Run': 10, 'Drive': 2})
This works because Counter.update() returns None. if None will always evaluate False and throw out that element. So this generates a side effect empty list [] as the only memory overhead. if False would work equally well.
Just use a dictionary! Note that in python it is idomatic to use snake_case for variables and keys.
travel_times = {'run': 0, 'walk': 0, 'drive': 0}
for item in items:
action, time = item['type'], item['time']
travel_times[action] += time

Categories