-1

For example, most_average([1, 2, 3, 4, 5]) should return 3 (the average of the numbers in the list is 3.0, and 3 is clearly closest to this). most_average([3, 4, 3, 1]) should also return 3 (the average is 2.75, and 3 is closer to 2.75 than is any other number in the list).

This is what I have right now:

def most_average(numbers):
    sum = 0
    for num in numbers:
        sum += num
        result = sum / len(numbers)
    return result

I can only get the normal average, but I don't know how to find the most closest number in the list.

wovano
  • 4,543
  • 5
  • 22
  • 49
JUDYCHAN
  • 1
  • 1
  • 1
    Does this answer your question? [How to find a value closest to another value X in a large sorted array efficiently](https://stackoverflow.com/questions/36143149/how-to-find-a-value-closest-to-another-value-x-in-a-large-sorted-array-efficient) – wovano Oct 30 '22 at 08:49
  • See also [From list of integers, get number closest to a given value](https://stackoverflow.com/questions/12141150/from-list-of-integers-get-number-closest-to-a-given-value) – wovano Oct 30 '22 at 08:54

3 Answers3

2

Combining pythons min function with the key option, this is a one-liner:

numbers = [1, 2, 3, 4, 5]
closest_to_avg = min(numbers, key=lambda x: abs(x - sum(numbers)/len(numbers)))
print(closest_to_avg)
# 3

Explanation, via break-down to more lines:

avg_of_numbers = sum(numbers) / len(numbers)
print(avg_of_numbers)
# 3

So the average can be calculated without any (explicit) loops.
Now what you need is to just calculate the absolute difference between each of numbers and the average:

abs_diffs_from_avg = [abs(x - avg_of_numbers) for x in numbers]

The number in numbers minimizing this diff is the number you want, and you can see this by looking at each number and its corresponding diff:

print([(x, abs(x - avg_of_numbers)) for x in numbers])
# contains the pair (3, 0.0), which is indeed the minimum in this case)

So you just pass this diff as the key to the min function...

(Regarding usage of the key input, this is defined as "a function to customize the sort order", and is used in sort, max, and other python functions. There are many explanations of this functionality, but for min it basically means "use this function to define the ordering of the list in ascending order, and then just take the first element".)

EDIT:

As recomended in the comment, the average should be calculated outside the min, so as to avoid recalculating. So now it's a two-liner ;-)

numbers = [1, 2, 3, 4, 5]

avg_of_numbers = sum(numbers) / len(numbers)
closest_to_avg = min(numbers, key=lambda x: abs(x - avg_of_numbers))

print(closest_to_avg)
# 3
ShlomiF
  • 2,686
  • 1
  • 14
  • 19
0

My idea is to subtract the average from the list of numbers, get the absolute value, and find the index of the minimum.

import numpy as np

a = [1, 2, 3, 4, 6]

avg = np.average(a)

print(f"Average of {a} is : {avg}")

dist_from_avg = np.abs(a - avg)

#get the index of the minimum
closest_idx = np.argmin(dist_from_avg)

print(f"Closest to average is : {a[closest_idx]}")

Which prints

Average of [1, 2, 3, 4, 6] is : 3.2
Closest to average is : 3
Fra93
  • 1,992
  • 1
  • 9
  • 18
  • 1
    I downvoted, because `numpy` is overkill for this. If the question is some simple arithmetic, then it should be solved with simple arithmetic. – Nathaniel Ford Oct 30 '22 at 08:59
  • 1
    I'd think this answer was more kosher if it had any description about why `dist_from_avg` works with `np.argmin()`. (The lack of typing here really occludes what is going on!) It relies heavily on the magic that numpy provides, without either referencing numpy documentation or gesturing to why this is an effective way to go about it. – Nathaniel Ford Oct 30 '22 at 09:22
0

This is pretty simple - get the average (mean) of your numbers, find the variance of each of your numbers, and which has the minimum variance (minimum). Then return the index of the element with that variance.

def most_average(ls: list[int]) -> int:
    mean = sum(ls) / len(ls)  # Figures out where the mean average is.
    variance = [abs(v - mean) for v in ls]  # Figures out how far from the mean each element in the list is.
    minimum = min(variance)  # Figures out what the smallest variance is (this is the number closest to the mean).
    return ls[variance.index(minimum)]  # Returns the element that has the minimal variance.

In the repl:

>>> most_average([1,2,3,4,5])
3

I will say that the expense here is that you're creating an entire new list in order to calculate and record the variance of every member of the original list. But, absent other constraints, this is the most straightforward way to think about it.

Some key functions that will help you here:

sum(<some list or iterable>) -> adds it all up
len(<some list or iterable>) -> the length of the iterable
abs(<some value>) -> If it is negative, make it positive
min(<some list or iterable>) -> Find the smallest value and return it
<list>.index(<value>) -> Get the index of the value you pass

The last is interesting here, because if you calculate all the variances, you can quickly index into the original list if you ask your variance list where the smallest value is. Because the map one to one, this maps into your original list.

There is a last caveat to mention - this cannot decide whether 2 or 3 is the closest value to the mean in the list [1,2,3,4]. You'll have to make a modification if the result is not 2.

Nathaniel Ford
  • 20,545
  • 20
  • 91
  • 102