0
\$\begingroup\$

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?

\$\endgroup\$

migrated from stackoverflow.com Oct 22 '15 at 16:20

This question came from our site for professional and enthusiast programmers.

  • \$\begingroup\$ I depends what do you mean with better way. Better with regard to beauty, time, long inputs,...? \$\endgroup\$ – wenzul Sep 23 '15 at 11:10
2
\$\begingroup\$

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) 
\$\endgroup\$
  • \$\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 Sep 23 '15 at 11:15
  • \$\begingroup\$ @wenzul How is "centered" average defined for less than 3 numbers? \$\endgroup\$ – Alex.S Sep 23 '15 at 11:19
  • \$\begingroup\$ @awkward101 Ok, skipped that. @Alex.S NotImplemented :) \$\endgroup\$ – wenzul Sep 23 '15 at 11:19
  • \$\begingroup\$ @wenzul Ok :) BTW it will not work if len(nums) == 2 but WILL work if len(nums) == 1 ;) \$\endgroup\$ – Alex.S Sep 23 '15 at 11:24
  • \$\begingroup\$ @Alex.S Hm, it depends on how the function will be defined. If you assume that nums[0] is both min and max should we throw it away? We should define a domain to solve that mathematical problem. :) \$\endgroup\$ – wenzul Sep 23 '15 at 11:27
4
\$\begingroup\$

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])
\$\endgroup\$
2
\$\begingroup\$

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.

\$\endgroup\$
  • 1
    \$\begingroup\$ For large lists, requesting the max and min separately will be more efficient than sorting and removing the first and last. \$\endgroup\$ – Karl Knechtel Sep 23 '15 at 11:02
  • \$\begingroup\$ You are right, of course. \$\endgroup\$ – honza_p Sep 23 '15 at 11:03
1
\$\begingroup\$

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)
\$\endgroup\$
  • \$\begingroup\$ This works only on sorted lists. \$\endgroup\$ – honza_p Sep 23 '15 at 11:11
  • \$\begingroup\$ @honza_p Please read the source code before downvote. \$\endgroup\$ – wenzul Sep 23 '15 at 11:11
  • \$\begingroup\$ Sorry, I usually automatically skip #'s when reading. \$\endgroup\$ – honza_p Sep 23 '15 at 11:12
  • 2
    \$\begingroup\$ @honza_p Are you a human or a machine? :) \$\endgroup\$ – wenzul Sep 23 '15 at 11:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.