I'm learning Python & practising from this site and here is the particular problem at hand:
Return the "centered" average of an array of ints, which we'll say is the mean average of the values, except ignoring the largest and smallest values in the array. If there are multiple copies of the smallest value, ignore just one copy, and likewise for the largest value. Use int division to produce the final average. You may assume that the array is length 3 or more.
centered_average([1, 2, 3, 4, 100])
→3
centered_average([1, 1, 5, 5, 10, 8, 7])
→5
centered_average([-10, -4, -2, -4, -2, 0])
→-3
My solution is as follows:
def centered_average(nums):
items = len(nums)
total = 0
high = max(nums)
low = min(nums)
for num in nums:
total += num
aveg = (total -high-low) / (items-2)
return aveg
The above code works fine. I want to ask more experienced programmers if this could be done in a better manner - or is this solution fine?
-
\$\begingroup\$ I depends what do you mean with better way. Better with regard to beauty, time, long inputs,...? \$\endgroup\$wenzul– wenzul2015年09月23日 11:10:00 +00:00Commented Sep 23, 2015 at 11:10
4 Answers 4
You can replace your for
-loop with
total = sum(nums)
There is also no need in internal variables. Therefore you can write your function in just one line:
def centered_average(nums):
return (sum(nums) - max(nums) - min(nums)) / (len(nums) - 2)
-
\$\begingroup\$ @wenzul in this particular case it does, as the problem states that I can assume the array length to be 3 or more \$\endgroup\$awkward101– awkward1012015年09月23日 11:15:42 +00:00Commented Sep 23, 2015 at 11:15
-
\$\begingroup\$ @wenzul How is "centered" average defined for less than 3 numbers? \$\endgroup\$Alex.S– Alex.S2015年09月23日 11:19:04 +00:00Commented Sep 23, 2015 at 11:19
-
\$\begingroup\$ @awkward101 Ok, skipped that. @Alex.S
NotImplemented
:) \$\endgroup\$wenzul– wenzul2015年09月23日 11:19:22 +00:00Commented Sep 23, 2015 at 11:19 -
\$\begingroup\$ @wenzul Ok :) BTW it will not work if
len(nums) == 2
but WILL work iflen(nums) == 1
;) \$\endgroup\$Alex.S– Alex.S2015年09月23日 11:24:08 +00:00Commented Sep 23, 2015 at 11:24 -
\$\begingroup\$ @Alex.S Hm, it depends on how the function will be defined. If you assume that
nums[0]
is bothmin
andmax
should we throw it away? We should define a domain to solve that mathematical problem. :) \$\endgroup\$wenzul– wenzul2015年09月23日 11:27:38 +00:00Commented Sep 23, 2015 at 11:27
This code can be written more concisely in a couple of ways:
You can use the sum
function rather than an explicit loop:
(sum(nums) - max(nums) - min(nums)) / (len(nums) - 2)
You could also use sorting and slicing to remove the extreme values, which is more concise but less efficient:
sum(sorted(nums)[1:-1]) / (len(nums) - 2)
The slice notation [1:-1]
takes the elements of a list starting with the second element (index 1) and finishing with the last-but-one element (index -1, i.e. indexing from the end of the list rather than the start)
If you are using Python 3.4+ you can use the statistics module, which has a mean
function:
from statistics import mean
mean(sorted(nums)[1:-1])
If you don't care too much about performance:
def centered_average(nums):
return sum(sorted(nums)[1:-1]) / (len(nums) - 2)
Otherwise look for the other answers.
-
1\$\begingroup\$ For large lists, requesting the
max
andmin
separately will be more efficient than sorting and removing the first and last. \$\endgroup\$Karl Knechtel– Karl Knechtel2015年09月23日 11:02:17 +00:00Commented Sep 23, 2015 at 11:02 -
\$\begingroup\$ You are right, of course. \$\endgroup\$honza_p– honza_p2015年09月23日 11:03:59 +00:00Commented Sep 23, 2015 at 11:03
You could just throw away the first and last element in your list:
def centered_average(nums):
#nums = sorted(nums) # if input is not always sorted
nums1 = nums[1:-1]
return sum(nums1) / len(nums1)
-
\$\begingroup\$ This works only on sorted lists. \$\endgroup\$honza_p– honza_p2015年09月23日 11:11:22 +00:00Commented Sep 23, 2015 at 11:11
-
\$\begingroup\$ @honza_p Please read the source code before downvote. \$\endgroup\$wenzul– wenzul2015年09月23日 11:11:44 +00:00Commented Sep 23, 2015 at 11:11
-
1\$\begingroup\$ Sorry, I usually automatically skip #'s when reading. \$\endgroup\$honza_p– honza_p2015年09月23日 11:12:58 +00:00Commented Sep 23, 2015 at 11:12
-
2\$\begingroup\$ @honza_p Are you a human or a machine? :) \$\endgroup\$wenzul– wenzul2015年09月23日 11:15:17 +00:00Commented Sep 23, 2015 at 11:15
-
\$\begingroup\$ I've just read lots of code \$\endgroup\$Anton K– Anton K2022年02月21日 07:08:15 +00:00Commented Feb 21, 2022 at 7:08