Finding the average of a list - python

How do I find the mean average of a list in Python?
[1, 2, 3, 4] ⟶ 2.5

For Python 3.8+, use statistics.fmean for numerical stability with floats. (Fast.)
For Python 3.4+, use statistics.mean for numerical stability with floats. (Slower.)
xs = [15, 18, 2, 36, 12, 78, 5, 6, 9]
import statistics
statistics.mean(xs) # = 20.11111111111111
For older versions of Python 3, use
sum(xs) / len(xs)
For Python 2, convert len to a float to get float division:
sum(xs) / float(len(xs))

xs = [15, 18, 2, 36, 12, 78, 5, 6, 9]
sum(xs) / len(xs)

Use numpy.mean:
xs = [15, 18, 2, 36, 12, 78, 5, 6, 9]
import numpy as np
print(np.mean(xs))

For Python 3.4+, use mean() from the new statistics module to calculate the average:
from statistics import mean
xs = [15, 18, 2, 36, 12, 78, 5, 6, 9]
mean(xs)

Why would you use reduce() for this when Python has a perfectly cromulent sum() function?
print sum(l) / float(len(l))
(The float() is necessary in Python 2 to force Python to do a floating-point division.)

There is a statistics library if you are using python >= 3.4
https://docs.python.org/3/library/statistics.html
You may use it's mean method like this. Let's say you have a list of numbers of which you want to find mean:-
list = [11, 13, 12, 15, 17]
import statistics as s
s.mean(list)
It has other methods too like stdev, variance, mode, harmonic mean, median etc which are too useful.

Instead of casting to float, you can add 0.0 to the sum:
def avg(l):
return sum(l, 0.0) / len(l)

EDIT:
I added two other ways to get the average of a list (which are relevant only for Python 3.8+). Here is the comparison that I made:
import timeit
import statistics
import numpy as np
from functools import reduce
import pandas as pd
import math
LIST_RANGE = 10
NUMBERS_OF_TIMES_TO_TEST = 10000
l = list(range(LIST_RANGE))
def mean1():
return statistics.mean(l)
def mean2():
return sum(l) / len(l)
def mean3():
return np.mean(l)
def mean4():
return np.array(l).mean()
def mean5():
return reduce(lambda x, y: x + y / float(len(l)), l, 0)
def mean6():
return pd.Series(l).mean()
def mean7():
return statistics.fmean(l)
def mean8():
return math.fsum(l) / len(l)
for func in [mean1, mean2, mean3, mean4, mean5, mean6, mean7, mean8 ]:
print(f"{func.__name__} took: ", timeit.timeit(stmt=func, number=NUMBERS_OF_TIMES_TO_TEST))
These are the results I got:
mean1 took: 0.09751558300000002
mean2 took: 0.005496791999999973
mean3 took: 0.07754683299999998
mean4 took: 0.055743208000000044
mean5 took: 0.018134082999999968
mean6 took: 0.6663848750000001
mean7 took: 0.004305374999999945
mean8 took: 0.003203333000000086
Interesting! looks like math.fsum(l) / len(l) is the fastest way, then statistics.fmean(l), and only then sum(l) / len(l). Nice!
Thank you #Asclepius for showing me these two other ways!
OLD ANSWER:
In terms of efficiency and speed, these are the results that I got testing the other answers:
# test mean caculation
import timeit
import statistics
import numpy as np
from functools import reduce
import pandas as pd
LIST_RANGE = 10
NUMBERS_OF_TIMES_TO_TEST = 10000
l = list(range(LIST_RANGE))
def mean1():
return statistics.mean(l)
def mean2():
return sum(l) / len(l)
def mean3():
return np.mean(l)
def mean4():
return np.array(l).mean()
def mean5():
return reduce(lambda x, y: x + y / float(len(l)), l, 0)
def mean6():
return pd.Series(l).mean()
for func in [mean1, mean2, mean3, mean4, mean5, mean6]:
print(f"{func.__name__} took: ", timeit.timeit(stmt=func, number=NUMBERS_OF_TIMES_TO_TEST))
and the results:
mean1 took: 0.17030245899968577
mean2 took: 0.002183011999932205
mean3 took: 0.09744236000005913
mean4 took: 0.07070840100004716
mean5 took: 0.022754742999950395
mean6 took: 1.6689282460001778
so clearly the winner is:
sum(l) / len(l)

sum(l) / float(len(l)) is the right answer, but just for completeness you can compute an average with a single reduce:
>>> reduce(lambda x, y: x + y / float(len(l)), l, 0)
20.111111111111114
Note that this can result in a slight rounding error:
>>> sum(l) / float(len(l))
20.111111111111111

I tried using the options above but didn't work.
Try this:
from statistics import mean
n = [11, 13, 15, 17, 19]
print(n)
print(mean(n))
worked on python 3.5

Or use pandas's Series.mean method:
pd.Series(sequence).mean()
Demo:
>>> import pandas as pd
>>> l = [15, 18, 2, 36, 12, 78, 5, 6, 9]
>>> pd.Series(l).mean()
20.11111111111111
>>>
From the docs:
Series.mean(axis=None, skipna=None, level=None, numeric_only=None, **kwargs)¶
And here is the docs for this:
https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.mean.html
And the whole documentation:
https://pandas.pydata.org/pandas-docs/stable/10min.html

I had a similar question to solve in a Udacity´s problems. Instead of a built-in function i coded:
def list_mean(n):
summing = float(sum(n))
count = float(len(n))
if n == []:
return False
return float(summing/count)
Much more longer than usual but for a beginner its quite challenging.

as a beginner, I just coded this:
L = [15, 18, 2, 36, 12, 78, 5, 6, 9]
total = 0
def average(numbers):
total = sum(numbers)
total = float(total)
return total / len(numbers)
print average(L)

If you wanted to get more than just the mean (aka average) you might check out scipy stats:
from scipy import stats
l = [15, 18, 2, 36, 12, 78, 5, 6, 9]
print(stats.describe(l))
# DescribeResult(nobs=9, minmax=(2, 78), mean=20.11111111111111,
# variance=572.3611111111111, skewness=1.7791785448425341,
# kurtosis=1.9422716419666397)

In order to use reduce for taking a running average, you'll need to track the total but also the total number of elements seen so far. since that's not a trivial element in the list, you'll also have to pass reduce an extra argument to fold into.
>>> l = [15, 18, 2, 36, 12, 78, 5, 6, 9]
>>> running_average = reduce(lambda aggr, elem: (aggr[0] + elem, aggr[1]+1), l, (0.0,0))
>>> running_average[0]
(181.0, 9)
>>> running_average[0]/running_average[1]
20.111111111111111

Both can give you close to similar values on an integer or at least 10 decimal values. But if you are really considering long floating values both can be different. Approach can vary on what you want to achieve.
>>> l = [15, 18, 2, 36, 12, 78, 5, 6, 9]
>>> print reduce(lambda x, y: x + y, l) / len(l)
20
>>> sum(l)/len(l)
20
Floating values
>>> print reduce(lambda x, y: x + y, l) / float(len(l))
20.1111111111
>>> print sum(l)/float(len(l))
20.1111111111
#Andrew Clark was correct on his statement.

suppose that
x = [
[-5.01,-5.43,1.08,0.86,-2.67,4.94,-2.51,-2.25,5.56,1.03],
[-8.12,-3.48,-5.52,-3.78,0.63,3.29,2.09,-2.13,2.86,-3.33],
[-3.68,-3.54,1.66,-4.11,7.39,2.08,-2.59,-6.94,-2.26,4.33]
]
you can notice that x has dimension 3*10 if you need to get the mean to each row you can type this
theMean = np.mean(x1,axis=1)
don't forget to import numpy as np

l = [15, 18, 2, 36, 12, 78, 5, 6, 9]
l = map(float,l)
print '%.2f' %(sum(l)/len(l))

Find the average in list
By using the following PYTHON code:
l = [15, 18, 2, 36, 12, 78, 5, 6, 9]
print(sum(l)//len(l))
try this it easy.

print reduce(lambda x, y: x + y, l)/(len(l)*1.0)
or like posted previously
sum(l)/(len(l)*1.0)
The 1.0 is to make sure you get a floating point division

Combining a couple of the above answers, I've come up with the following which works with reduce and doesn't assume you have L available inside the reducing function:
from operator import truediv
L = [15, 18, 2, 36, 12, 78, 5, 6, 9]
def sum_and_count(x, y):
try:
return (x[0] + y, x[1] + 1)
except TypeError:
return (x + y, 2)
truediv(*reduce(sum_and_count, L))
# prints
20.11111111111111

I want to add just another approach
import itertools,operator
list(itertools.accumulate(l,operator.add)).pop(-1) / len(l)

You can make a function for averages, usage:
average(21,343,2983) # You can pass as many arguments as you want.
Here is the code:
def average(*args):
total = 0
for num in args:
total+=num
return total/len(args)
*args allows for any number of answers.

Simple solution is a avemedi-lib
pip install avemedi_lib
Than include to your script
from avemedi_lib.functions import average, get_median, get_median_custom
test_even_array = [12, 32, 23, 43, 14, 44, 123, 15]
test_odd_array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Getting average value of list items
print(average(test_even_array)) # 38.25
# Getting median value for ordered or unordered numbers list
print(get_median(test_even_array)) # 27.5
print(get_median(test_odd_array)) # 27.5
# You can use your own sorted and your count functions
a = sorted(test_even_array)
n = len(a)
print(get_median_custom(a, n)) # 27.5
Enjoy.

numbers = [0,1,2,3]
numbers[0] = input("Please enter a number")
numbers[1] = input("Please enter a second number")
numbers[2] = input("Please enter a third number")
numbers[3] = input("Please enter a fourth number")
print (numbers)
print ("Finding the Avarage")
avarage = int(numbers[0]) + int(numbers[1]) + int(numbers[2]) + int(numbers [3]) / 4
print (avarage)

Related

How to print smallest number from list when mode is not available?

I Would like to find Mode in python array or list, but if all numbers appears at only once(or we can say there is no Mode) I wanted to print smallest number.
n_num = [64630, 11735, 14216, 99233, 14470, 4978, 73429, 38120, 51135, 67060]
from statistics import mode
def mode(n_num):
n_num.sort()
m = min(n_num)
return m
print(str(mode(n_num)))
You can use multimode() from the statistics package instead of mode(). This will return multiple values when there is more than one mode to choose from. You can take the min() from that:
from statistics import multimode
n_num = [10, 9, 1, 2, 3, 4]
min(multimode(n_num))
# 1
n_num = [10, 9, 1, 2, 3, 4, 9, 10 ]
min(multimode(n_num))
#9
[Note: this requires python 3.8]
try to use the try statement
import statistics
def special_mode(iterable):
try:
result = statistics.mode(iterable)
except statistics.StatisticsError: # if mode() fail, it do min()
result = min(iterable)
return result
mylist = [0, 1, 6, 9, 1, -7]
print(special_mode(mylist))
# return the 1 because of the mode function
mylist = [0, 1, 6, 9, -7]
print(special_mode(mylist))
# return the -7 beacuse it's the smallest
hope it was helpful
Python already has a min and max function built-in to find the smallest and largest values in a list
n = [64630, 11735, 14216, 99233, 14470, 4978, 73429, 38120, 51135, 67060]
smallest_number = min(n)
largest_number = max(n)

How to calculate Features from List of Numpy arrays with different array length? [duplicate]

How do I find the mean average of a list in Python?
[1, 2, 3, 4] ⟶ 2.5
For Python 3.8+, use statistics.fmean for numerical stability with floats. (Fast.)
For Python 3.4+, use statistics.mean for numerical stability with floats. (Slower.)
xs = [15, 18, 2, 36, 12, 78, 5, 6, 9]
import statistics
statistics.mean(xs) # = 20.11111111111111
For older versions of Python 3, use
sum(xs) / len(xs)
For Python 2, convert len to a float to get float division:
sum(xs) / float(len(xs))
xs = [15, 18, 2, 36, 12, 78, 5, 6, 9]
sum(xs) / len(xs)
Use numpy.mean:
xs = [15, 18, 2, 36, 12, 78, 5, 6, 9]
import numpy as np
print(np.mean(xs))
For Python 3.4+, use mean() from the new statistics module to calculate the average:
from statistics import mean
xs = [15, 18, 2, 36, 12, 78, 5, 6, 9]
mean(xs)
Why would you use reduce() for this when Python has a perfectly cromulent sum() function?
print sum(l) / float(len(l))
(The float() is necessary in Python 2 to force Python to do a floating-point division.)
There is a statistics library if you are using python >= 3.4
https://docs.python.org/3/library/statistics.html
You may use it's mean method like this. Let's say you have a list of numbers of which you want to find mean:-
list = [11, 13, 12, 15, 17]
import statistics as s
s.mean(list)
It has other methods too like stdev, variance, mode, harmonic mean, median etc which are too useful.
Instead of casting to float, you can add 0.0 to the sum:
def avg(l):
return sum(l, 0.0) / len(l)
EDIT:
I added two other ways to get the average of a list (which are relevant only for Python 3.8+). Here is the comparison that I made:
import timeit
import statistics
import numpy as np
from functools import reduce
import pandas as pd
import math
LIST_RANGE = 10
NUMBERS_OF_TIMES_TO_TEST = 10000
l = list(range(LIST_RANGE))
def mean1():
return statistics.mean(l)
def mean2():
return sum(l) / len(l)
def mean3():
return np.mean(l)
def mean4():
return np.array(l).mean()
def mean5():
return reduce(lambda x, y: x + y / float(len(l)), l, 0)
def mean6():
return pd.Series(l).mean()
def mean7():
return statistics.fmean(l)
def mean8():
return math.fsum(l) / len(l)
for func in [mean1, mean2, mean3, mean4, mean5, mean6, mean7, mean8 ]:
print(f"{func.__name__} took: ", timeit.timeit(stmt=func, number=NUMBERS_OF_TIMES_TO_TEST))
These are the results I got:
mean1 took: 0.09751558300000002
mean2 took: 0.005496791999999973
mean3 took: 0.07754683299999998
mean4 took: 0.055743208000000044
mean5 took: 0.018134082999999968
mean6 took: 0.6663848750000001
mean7 took: 0.004305374999999945
mean8 took: 0.003203333000000086
Interesting! looks like math.fsum(l) / len(l) is the fastest way, then statistics.fmean(l), and only then sum(l) / len(l). Nice!
Thank you #Asclepius for showing me these two other ways!
OLD ANSWER:
In terms of efficiency and speed, these are the results that I got testing the other answers:
# test mean caculation
import timeit
import statistics
import numpy as np
from functools import reduce
import pandas as pd
LIST_RANGE = 10
NUMBERS_OF_TIMES_TO_TEST = 10000
l = list(range(LIST_RANGE))
def mean1():
return statistics.mean(l)
def mean2():
return sum(l) / len(l)
def mean3():
return np.mean(l)
def mean4():
return np.array(l).mean()
def mean5():
return reduce(lambda x, y: x + y / float(len(l)), l, 0)
def mean6():
return pd.Series(l).mean()
for func in [mean1, mean2, mean3, mean4, mean5, mean6]:
print(f"{func.__name__} took: ", timeit.timeit(stmt=func, number=NUMBERS_OF_TIMES_TO_TEST))
and the results:
mean1 took: 0.17030245899968577
mean2 took: 0.002183011999932205
mean3 took: 0.09744236000005913
mean4 took: 0.07070840100004716
mean5 took: 0.022754742999950395
mean6 took: 1.6689282460001778
so clearly the winner is:
sum(l) / len(l)
sum(l) / float(len(l)) is the right answer, but just for completeness you can compute an average with a single reduce:
>>> reduce(lambda x, y: x + y / float(len(l)), l, 0)
20.111111111111114
Note that this can result in a slight rounding error:
>>> sum(l) / float(len(l))
20.111111111111111
I tried using the options above but didn't work.
Try this:
from statistics import mean
n = [11, 13, 15, 17, 19]
print(n)
print(mean(n))
worked on python 3.5
Or use pandas's Series.mean method:
pd.Series(sequence).mean()
Demo:
>>> import pandas as pd
>>> l = [15, 18, 2, 36, 12, 78, 5, 6, 9]
>>> pd.Series(l).mean()
20.11111111111111
>>>
From the docs:
Series.mean(axis=None, skipna=None, level=None, numeric_only=None, **kwargs)¶
And here is the docs for this:
https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.mean.html
And the whole documentation:
https://pandas.pydata.org/pandas-docs/stable/10min.html
I had a similar question to solve in a Udacity´s problems. Instead of a built-in function i coded:
def list_mean(n):
summing = float(sum(n))
count = float(len(n))
if n == []:
return False
return float(summing/count)
Much more longer than usual but for a beginner its quite challenging.
as a beginner, I just coded this:
L = [15, 18, 2, 36, 12, 78, 5, 6, 9]
total = 0
def average(numbers):
total = sum(numbers)
total = float(total)
return total / len(numbers)
print average(L)
If you wanted to get more than just the mean (aka average) you might check out scipy stats:
from scipy import stats
l = [15, 18, 2, 36, 12, 78, 5, 6, 9]
print(stats.describe(l))
# DescribeResult(nobs=9, minmax=(2, 78), mean=20.11111111111111,
# variance=572.3611111111111, skewness=1.7791785448425341,
# kurtosis=1.9422716419666397)
In order to use reduce for taking a running average, you'll need to track the total but also the total number of elements seen so far. since that's not a trivial element in the list, you'll also have to pass reduce an extra argument to fold into.
>>> l = [15, 18, 2, 36, 12, 78, 5, 6, 9]
>>> running_average = reduce(lambda aggr, elem: (aggr[0] + elem, aggr[1]+1), l, (0.0,0))
>>> running_average[0]
(181.0, 9)
>>> running_average[0]/running_average[1]
20.111111111111111
Both can give you close to similar values on an integer or at least 10 decimal values. But if you are really considering long floating values both can be different. Approach can vary on what you want to achieve.
>>> l = [15, 18, 2, 36, 12, 78, 5, 6, 9]
>>> print reduce(lambda x, y: x + y, l) / len(l)
20
>>> sum(l)/len(l)
20
Floating values
>>> print reduce(lambda x, y: x + y, l) / float(len(l))
20.1111111111
>>> print sum(l)/float(len(l))
20.1111111111
#Andrew Clark was correct on his statement.
suppose that
x = [
[-5.01,-5.43,1.08,0.86,-2.67,4.94,-2.51,-2.25,5.56,1.03],
[-8.12,-3.48,-5.52,-3.78,0.63,3.29,2.09,-2.13,2.86,-3.33],
[-3.68,-3.54,1.66,-4.11,7.39,2.08,-2.59,-6.94,-2.26,4.33]
]
you can notice that x has dimension 3*10 if you need to get the mean to each row you can type this
theMean = np.mean(x1,axis=1)
don't forget to import numpy as np
l = [15, 18, 2, 36, 12, 78, 5, 6, 9]
l = map(float,l)
print '%.2f' %(sum(l)/len(l))
Find the average in list
By using the following PYTHON code:
l = [15, 18, 2, 36, 12, 78, 5, 6, 9]
print(sum(l)//len(l))
try this it easy.
print reduce(lambda x, y: x + y, l)/(len(l)*1.0)
or like posted previously
sum(l)/(len(l)*1.0)
The 1.0 is to make sure you get a floating point division
Combining a couple of the above answers, I've come up with the following which works with reduce and doesn't assume you have L available inside the reducing function:
from operator import truediv
L = [15, 18, 2, 36, 12, 78, 5, 6, 9]
def sum_and_count(x, y):
try:
return (x[0] + y, x[1] + 1)
except TypeError:
return (x + y, 2)
truediv(*reduce(sum_and_count, L))
# prints
20.11111111111111
I want to add just another approach
import itertools,operator
list(itertools.accumulate(l,operator.add)).pop(-1) / len(l)
You can make a function for averages, usage:
average(21,343,2983) # You can pass as many arguments as you want.
Here is the code:
def average(*args):
total = 0
for num in args:
total+=num
return total/len(args)
*args allows for any number of answers.
Simple solution is a avemedi-lib
pip install avemedi_lib
Than include to your script
from avemedi_lib.functions import average, get_median, get_median_custom
test_even_array = [12, 32, 23, 43, 14, 44, 123, 15]
test_odd_array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Getting average value of list items
print(average(test_even_array)) # 38.25
# Getting median value for ordered or unordered numbers list
print(get_median(test_even_array)) # 27.5
print(get_median(test_odd_array)) # 27.5
# You can use your own sorted and your count functions
a = sorted(test_even_array)
n = len(a)
print(get_median_custom(a, n)) # 27.5
Enjoy.
numbers = [0,1,2,3]
numbers[0] = input("Please enter a number")
numbers[1] = input("Please enter a second number")
numbers[2] = input("Please enter a third number")
numbers[3] = input("Please enter a fourth number")
print (numbers)
print ("Finding the Avarage")
avarage = int(numbers[0]) + int(numbers[1]) + int(numbers[2]) + int(numbers [3]) / 4
print (avarage)

making a new modified version of a list without modifying the original list in python

i need to modify the contents of my og list into a different list w/out actually changing my og list.
def createList(numbers):
my_List= [0] * numbers
for q in range(0, len(my_List)):
myList[q]= randint (1, 21)
q=q+1
return my_List
def modifyList(newList):
for i in range(0, len(newList)):
if i % 2 == 0:
newList[i]= newList[i] / 2
else:
newList[i]= newList[i] * 2
return newList
def main():
my_List= createList(10)
print my_List
newList= modifyList(my_List)
print my_List
print newList
You need to make a copy of the list that is inputted to the modifyList function. This copy isn't done with myList[:] as you are not working with myList here! You are working with a different variable called newList which you need to make a copy of.
You need to remember that a function works with a variable that is passed into it but under the name it has been assigned in the function definition. So here, even though you only call the function with modifyList(myList), inside the function, you are always working with newList so trying to do anything with myList here will throw an error saying its undefined.
def modifyList(newList):
newList = newList[:]
for j in range(0, len(newList)):
if j % 2 == 0:
newList[j]= newList[j] / 2
else:
newList[j]= newList[j] * 2
return newList
Here's an alternate way, with list comprehensions. In Python, you usually don't have to create a list with placeholders and put the elements one by one:
>>> from random import randint
>>> my_list = [randint(1, 20) for _ in range(10)]
>>> my_list
[1, 20, 2, 4, 8, 12, 16, 7, 4, 14]
>>> [x * 2 if i % 2 else x / 2 for i, x in enumerate(my_list)]
[0.5, 40, 1.0, 8, 4.0, 24, 8.0, 14, 2.0, 28]
If you want to modify the original list in place, you could use numpy and advanced slicing:
>>> import numpy as np
>>> a = np.array([11, 13, 21, 12, 18, 2, 21, 1, 5, 9])
>>> a[::2] = a[::2] / 2
>>> a[1::2] = a[1::2] * 2
>>> a
array([ 5, 26, 10, 24, 9, 4, 10, 2, 2, 18])

Method to get the max distance (step) between values in python?

Given an list of integers does exists a default method find the max distance between values?
So if I have this array
[1, 3, 5, 9, 15, 30]
The max step between the values is 15. Does the list object has a method for do that?
No, list objects have no standard "adjacent differences" method or the like. However, using the pairwise function mentioned in the itertools recipes:
def pairwise(iterable):
a, b = tee(iterable)
next(b, None)
return izip(a, b)
...you can (concisely and efficiently) define
>>> max(b-a for (a,b) in pairwise([1, 3, 5, 9, 15, 30]))
15
No, but it's trivial to code:
last = data[0]
dist = 0
for i in data[1:]:
dist = max(dist, i-last)
last = i
return dist
You can do:
>>> s = [1, 3, 5, 9, 15, 30]
>>> max(x[0] - x[1] for x in zip(s[1:], s))
15
This uses max and zip. It computes the difference between all consecutive elements and returns the max of those.
l=[1, 3, 5, 9, 15, 30]
max([j-i for i, j in zip(l[:-1], l[1:])])
That is using pure python and gives you the desired output "15".
If you like to work with "numpy" you could do:
import numpy as np
max(np.diff(l))
The list object does not. However, it is pretty quick to write a function that does that:
def max_step(my_list):
max_step = 0
for ind in xrange(len(my_list)-1):
step = my_list[ind+1] - my_list[ind]
if step > max_step:
max_step = step
return max_step
>>> max_step([1, 3, 5, 9, 15, 30])
15
Or if you prefer even shorter:
max_step = lambda l: max([l[i+1] - l[i] for i in xrange(len(l)-1)])
>>> max_step([1, 3, 5, 9, 15, 30])
15
It is possible to use the reduce() function, but it is not that elegant as you need some way to keep track of the previous value:
def step(maxStep, cur):
if isinstance(maxStep, int):
maxStep = (abs(maxStep-cur), cur)
return (max(maxStep[0], abs(maxStep[1]-cur)), cur)
l = [1, 3, 5, 9, 15, 30]
print reduce(step, l)[0]
The solution works by returing the previous value and the accumulated max calculation as a tuple for each iteration.
Also what is the expected outcome for [10,20,30,5]? Is it 10 or 25? If 25 then you need to add abs() to your calculation.

Odd behavior of stacked filter() calls

So I'm getting some interesting behaviour from some filters stacked within a for loop.
I'll start with a demonstration:
>>> x = range(100)
>>> x = filter(lambda n: n % 2 == 0, x)
>>> x = filter(lambda n: n % 3 == 0, x)
>>> list(x)
[0, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96]
Here we get the expected output. We have a range within a filter within a filter, and the filter conditions are stacking as we want them to. Now here comes my problem.
I have written a function for calculating the relative primes of a number. It looks like this:
def relative_primes(num):
'''Returns a list of relative primes, relative to the given number.'''
if num == 1:
return []
elif is_prime(num):
return list(range(1, num))
result = range(1, num)
for factor in prime_factors(num):
# Why aren't these filters stacking properly?
result = filter(lambda n: n % factor != 0, result)
return list(result)
For whatever reason, the filter is only being applied to the LAST factor in the list acquired from prime_factors(). Example:
>>> prime_factors(30)
[2, 3, 5]
>>> relative_primes(30)
[1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29]
We can see that no multiples of 2 or 3 were removed from the list. Why is this happening? Why does the above example work, but the filters in the for loop don't?
In Python 3.x, filter() returns a generator instead of a list. As such, only the final value of factor gets used since all three filters use the same factor. You will need to modify your lambda slightly in order to make it work.
result = filter(lambda n, factor=factor: n % factor != 0, result)
The evaluation of the iterators is lazy. All filters will be evaluated only in the statement
return list(result)
By that time, the value of factor is the last prime factor. The lambda functions only contain a reference to the local name factor and will use whatever value is assigned to that name at the time of execution.
One way to fix this is to convert to a list in every iteration.
As a sidenote, a much easier implementation of this function is
from fractions import gcd
def relative_primes(n):
return [i for i in range(1, n) if gcd(n, i) == 1]
Edit: If you are after performance instead of simplicity, you can also try this one:
def relative_primes(n):
sieve = [1] * n
for i in range(2, n):
if not sieve[i] or n % i:
continue
sieve[::i] = [0] * (n // i)
return list(itertools.compress(range(n), sieve))
If I understood you correctly and Two integers are relatively prime if they share no common positive factors (divisors) except 1. Using the notation to denote the greatest common divisor, two integers a and b are relatively prime if gcd(a,b)==1. then you can use the fractions module in the following way.
from fractions import gcd
num = 30
relative_primes = filter(lambda x: gcd(x,num) == 1, xrange(1,num))

Categories

Resources