2
\$\begingroup\$

The code returns the mean of a list of integers, except ignoring the largest and smallest values in the list. If there are multiple copies of the smallest value, ignore just one copy, and likewise for the largest value. Assume that the list is length 3 or more.

For this problem, as part of my learning, I’ve defined my own functions. Please comment on my variable names, docstrings, readability of code etc. and let me know how you would do it.

from typing import Sequence

def find_length(seq: Sequence) -> int:
    """ Return the number of elements in a sequence.

    >>> numbers = [-10, -4, -2, -4, -2, 0]
    >>> find_length(numbers)
    6
    """

    count = 0
    for _ in seq:
        count += 1

    return count


def find_min(numbers: Sequence) -> int:
    """ Return the smallest number in a sequence.

    >>> numbers = [-10, -4, -2, -4, -2, 0]
    >>> find_min(numbers)
    -10
    """    

    min_number = numbers[0]

    for number in numbers:
        if number < min_number:
            min_number = number

    return min_number


def find_max(numbers: Sequence) -> int:
    """ Return the biggest number in a sequence.

    >>> numbers = [-10, -4, -2, -4, -2, 0]
    >>> find_max(numbers)
    0
    """

    max_number = numbers[0]    

    for number in numbers:
        if number > max_number:
            max_number = number

    return max_number


def find_sum(numbers: Sequence) -> int:
    """ Return sum of the numbers in a sequence.

    >>> numbers = [-10, -4, -2, -4, -2, 0]
    >>> find_sum(numbers)
    -22
    """

    total = 0

    for number in numbers:
        total += number

    return total


def find_centered_average(numbers: Sequence) -> int:
    """ Return the centered average of a list of numbers.

    >>> numbers = [-10, -4, -2, -4, -2, 0]
    >>> find_centered_average(numbers)
    -3
    """

    max_number = find_max(numbers)
    min_number = find_min(numbers)    
    total = find_sum(numbers) - max_number - min_number
    centered_average = total // (find_length(numbers) - 2)

    return centered_average

All of that can be accomplished with either:

(sum(numbers) - max(numbers) - min(numbers)) // (len(numbers) - 2)

Or,

centered_numbers = sorted(numbers)[1:-1]
sum(centered_numbers) // len(centered_numbers))

There must be a number of other ways to do it.

\$\endgroup\$
  • 2
    \$\begingroup\$ Well, your first alternative is what I would have suggested to change your code to... \$\endgroup\$ – Graipher Oct 11 '17 at 16:14
  • \$\begingroup\$ @Graipher, ha ha, I know it's fairly straightforward. The second alternative is also not bad, right? \$\endgroup\$ – Srisaila Oct 11 '17 at 16:24
  • \$\begingroup\$ @BarryCarter, please see repl.it/M5AN/1. Is that how you would do it? \$\endgroup\$ – Srisaila Oct 12 '17 at 3:37
  • \$\begingroup\$ @BarryCarter Please do not answer in comments. \$\endgroup\$ – 200_success Oct 12 '17 at 6:30
  • 1
    \$\begingroup\$ @srig Yes, though it now occurs to me you could calculate the sum and the mean in the same subroutine. Basically, it's faster to compute these values together than separately. \$\endgroup\$ – Barry Carter Oct 12 '17 at 14:48
5
\$\begingroup\$

Well, whenever you want to know which function is better, you should test them.

First, your custom functions are just re-inventing the wheel, so you should only use them if you have to (either because it is mandated or they are actually faster, more secure, more memory-friendly, more whatever).

When running your functions with growing number of numbers, this is what I get:

enter image description here

Here, Input is the length of the numbers list, generated with numpy.random.random_integers(-10, 10, size=n), with \$n\in [10, 10000]\$.

So, for larger lists, the difference between your own function and the sorting function is negligible. The sorting should be \$\mathcal{O}(n\log n)\$, but I don't see why your function seems to show a similar behavior.

The sum/min/max function should be \$\mathcal{O}(3n)\$, so wins for large lists.

For smaller sizes, the two simple implementations perform similarly and your functions slightly slower:

enter image description here

This is for numpy.random.random_integers(-100, 100, size=n), with \$n\in [10, 100]\$.

All measurements were done in Python 2.7.13. I put your last two snippets into functions:

def centered_average_sum(numbers):
    return (sum(numbers) - max(numbers) - min(numbers)) // (len(numbers) - 2)


def centered_average_sort(numbers):
    centered_numbers = sorted(numbers)[1:-1]
    return sum(centered_numbers) // len(centered_numbers)

Note that I fixed a superfluous closing bracket on the second function.

\$\endgroup\$
  • \$\begingroup\$ I was using print() on my machine and I'd removed it before posting this, but forgot the closing parenthesis :) \$\endgroup\$ – Srisaila Oct 11 '17 at 16:40

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.