Why is my median incorrect?

Hi All,

Just wanted to share my piece of code that is a very short version of the solution for this exercise:

def median(numbers):
  slist = sorted(numbers)
  nr = len(numbers)
  factor = 1 - nr % 2

  return (float(slist[ int(nr/2 - factor)]) + slist[int(nr/2)])/2

print median([4,5,5,4])

I hope you find this useful.

4 Likes
def median(nums):
  
  nums.sort()
  length = len(nums)
  halfNum = (length / 2) - 1
  if length == 1:
    answer1 = nums[0]
    
    return answer1
  
  elif length % 2 == 0:
    
    newNums = nums
    digit1 = newNums[halfNum]
    digit2 = nums[halfNum + 1]
    result = (digit1 + digit2) / 2.0
    
    return result
  else:
    oddanswer = nums[halfNum + 1]
    return oddanswer

This code works I just had to learn a few things, like len() returns a number not zero based answer, or I had to compensate for that.

halfNum = (length / 2) - 1
had to subtract 1 from the len() number to match the list[index]

Next was if I create a variable with variable = list.sort() I get (none type? item?) Whatever it was it always caused a error about (none type).

nums.sort() instead of x =nums.sort()
just putting this line in without making it a variable resulted in the list [nums] being permanently sorted, I did not realize that it changed it so i didnt have to make it a variable.

Things to keep in mind. This code is really novice and any constructive criticism is welcome.

2 Likes

The only problem with this is it modifies the middle element of an odd length list.

>>> print (median([7,4,5,3,5,4,6]))
5.0
>>> 

There is no 5.0 in that list. We should be returning the actual value, not a modified value.

That’s some pretty busy code for such a simple problem.

result = 0
def median(order):
mid = len(order) / 2 - 1
sort = sorted(order)
length = len(sort)
if length % 2 != 0:
return sort[mid]
else:
val1 = sort[mid]
val2 = sort[mid + 1]
global result
result = result + (val1 + val2) / 2.0
return result

print median([1])
print median([1, 2, 3])
print median([4, 5, 5, 4])
print median([1, 1, 2])
print median([3, 4, 9, 1])

I don’t know why this code doesn’t work. Can someone please help?

There are two possible solutions, depending upon the length of the sampe list. Can you solve one OR the other, then resolve this into something that can solve for both?

Could anyone advise why my code would be incorrect below?
I’m wondering why ‘-1’ is not included in the answer given by Codecademy.

def median(int_list):
  result = ''
  list_sorted = sorted(int_list)
  
  if len(int_list)%2 != 0:
  # if the length is odd
    result = list_sorted[(len(list_sorted)//2)-1]
    # Why don't I need '-1'?
    return result

  else:
  # if the length is even
    result = float((list_sorted[len(list_sorted)/2] + list_sorted[(len(list_sorted)/2)-1])/2.0)
    return result

why would you need -1?

If a list has a length of 3, the indexes/indices are: 0, 1, 2.
3 // 2 = 1
1 is the middle index. Subtracting one will now result in the wrong index, thus the wrong value.

for each list with odd/uneven length, you can apply this logic (you can try the math yourself for a list with a length of 5, 7, 9 and so forth)

Hi,

I just wanted to know if there was a better way I could have approached this problem. It seems very bloated with trying to get the middle indices. My code below works, just wondering if there is something I could have done differently.

def median(lis):
lis.sort()
if len(lis) % 2 == 0: #even
num = (lis[len(lis) / 2] + lis[(len(lis) / 2) - 1]) / 2.0
else: #odd
num = lis[(len(lis) - 1) / 2]
return num

Thanks!

1 Like

A pencil and paper are great to have on hand for this type of problem, in terms of visualization.

[ , , , , , , , , ]

Which element or pair of elements is/are in the middle? What is its index?

sample = [ 41, 94, 38, 76, 59, 25, 19, 63, 81 ]

Count the number of elements.

n = len(sample)

Remember that the first element is index 0. Using integer (or floor) division, find the middle index (or upper pair index).

m = n // 2

In our visual above, what is the index of the middle element? What is m when n is floor divided by 2? 4?

Thanks to fellows like Martin Richards and Edsger W. Dijkstra
we have zero-indexing offering up another advantage in that the quotient of integer division (by 2) of the length of the list either gives us the middle index, or the upper of the two middle indices.

# s = sorted(sample)
return s[m] if n % 2 else (s[m - 1] + s[m]) / 2    # 59

Note: divide by 2.0 if Python 2

One key point to remember when looking for ways to simplify is to identify and cache key data so there are no recurrent patterns. An identity will fill in where needed. Note our m and n variables. There are no methods in the return statement.

I commented out the sort line because it is important for us to see (visualize) the middle element(s) of a list, whether sorted or not. Note that we cached the important data before sorting.

Consider also that the list we are computing the median of may be sensitive to changes. That’s why I use sorted so the parameter is only copied, not mutated. That would re-order the original list and possibly cause problems somewhere else in the program. Lesson here is to never mutate a list in a function unless that is the specific intention. Finding the median of a list does not imply that intention. Best leave the argument list intact.

1 Like

Okay so I’ve failed on the first step lol:

def median(x):
  print x.sort()

median([9, 2, 11, 16, 8, 9])

This returns ‘None’

what does this refer to? the .sort() method or your median function?

if you refer to the .sort() method, have you checked the python documentation about the sort method?

And further to that, consider the state of the list that is passed into the function. Do we wish to preserve its order? If so, the list.sort() method is not the tool to reach for as it will alter the order of the original list. Our functions should only mutate global objects when that is our strictest of intention, else leave things as they are.

2 Likes

I have checked and realized I should be using ‘sorted()’ instead. I also read that ‘.sort()’ gives ‘None’ in the console, which is what happened for me.

Do I need to know or care about why this is?

Other than that, thanks!

i would care, sort() orders the list in memory and return None

where as sorted returns a new list.

Like mtf says, if we use .sort(), we modify the original list, is this desirable?

1 Like

Hi,

Thanks for explaining the difference between the two. I have another question - what would be wrong in modifying the original list? below is my code that worked, and following that is code using the ‘.sort()’ function (that didn’t work).

def median(x):
  chrono = sorted(x)
  mid_pt = len(chrono)//2
  if len(x) % 2 == 0:
    even_median = (chrono[mid_pt] + chrono[mid_pt - 1]) / 2.0
    return even_median
  
  elif len(x) == 1:
    return chrono[0]

  else:
    odd_median = chrono[mid_pt]
    return odd_median
  
    

print median([10, 2, 11, 16, 8, 9])

Second set of code:


def median(x):
  chrono = x.sort()
  mid_pt = len(chrono)//2
  if len(x) % 2 == 0:
    even_median = (chrono[mid_pt] + chrono[mid_pt - 1]) / 2.0
    return even_median
  
  elif len(x) == 1:
    return chrono[0]

  else:
    odd_median = chrono[mid_pt]
    return odd_median
  
    

print median([10, 2, 11, 16, 8, 9])

Also,

I’m struggling to understand why the ‘.sort()’ function returns ‘None’ - surely it should just return the sorted (new) version of the list? In addition, when we would ever need it?

sort is an insitu method that does not create a copy. It sorts the actual list. To assign it, use sorted.

chrono = sorted(x)

This will create a copy of the list, then sort it, then assign it.

Further to this, using sorted does not affect the original global object’s order. Something we need to keep in mind. The order of the global object may be important as it could be the sequence of events, and therefore a record of occurrence.

How come this prints False? I wrote down ‘print median(1)’ because it said that False would appear when it was printed.

def median(last):
  result = 0
  if len(lst) == 0:
    return result
  elif len(lst) == 1:
    return result == lst
  elif len(lst) == 2:
    return result == (lst[0] + lst[1]) / 2
  lst = sorted(lst)
  if len(lst) % 2 != 0:
    return result == lst[((len(lst) - 1) / 2) + 1]
  else:
    return result == (lst[len(lst) / 2] + lst[(len(lst) / 2) + 1]) / 2
  
print median([1])

this is the bit of code that should be executed:

elif len(lst) == 1:
    return result == lst

we could use a print statement to see this is actually happening, and then also use this to inspect the values:

elif len(lst) == 1:
    print result, lst
    return result == lst

Oh okay, thanks for the help