Median Python version issue?


#1


https://www.codecademy.com/courses/python-intermediate-en-rCQKw/2/5?curriculum_id=4f89dab3d788890003000096#

Stuck on the median problem. My code works fine in my IDE which is Python 3.5.2 but I believe these lessons are in Python 2.x

It was stuck on median([4, 5, 5, 4]) returned 4 instead of 4.5 for a while until I changed from integer to float division and now it gives me the error message median([6, 8, 12, 2, 23]) returned 6 instead of 8

Here is what my code looks like:

def median(sequence):
    sequence = sorted(sequence)
    if (((len(sequence)) % 2) > 0):
        return sequence[int((((len(sequence)) / 2) - .5))]
    else:
        return (((sequence[int(len(sequence)/2-1)])+(sequence[int(len(sequence)/2)]))/2.0)


#2

What if you also defined the length itself in a variable?

length = len(sequence)

Perhaps if you simplified your approach to the problem and added an elif statement.

You need to check if the length is equal to 1, and if so return the number at the first index.

sequence[0]

elif the median is two numbers, what is those two numbers divided by two?

(sequence[length / 2] + sequence[(length / 2) -1]) / (2.0)

else return the median number

sequence[length / 2]

Here is an example of code that works as described:

def median(numbers):
    num = sorted(numbers)
    length = len(num)
    if length == 1:
        return num[0]
    elif length % 2 == 0:
        return (num[length / 2] + num[(length / 2) -1]) / (2.0)
        
    else:
        return num[length / 2]

#3

Thanks for the suggestions Alan.

I didn't make a variable for len(sequence) because len(sequence) works the same and doesn't require that I refer back to a variable declaration to remember what it is. My if else statement functions as you described, except I don't check for len(sequence) == 1 because it works without this special check.

Turns out I only changed one instance of integer division to float and needed to make that change for all the times I divided by 2.

Passing code ended up looking like this:

def median(sequence):
    sequence = sorted(sequence)
    if (((len(sequence)) % 2) > 0):
        return sequence[int((((len(sequence)) / 2.0) - .5))]
    else:
        return (((sequence[int(len(sequence)/2.0-1)])+(sequence[int(len(sequence)/2.0)]))/2.0)

#4

I'm glad you were able to make it work. I like that there are so many ways to skin the proverbial cat.


#5

This is convoluted, and deserves a re-think. Why divide by an arbitrary float only to convert to an integer? What's with the correction... - .5 ?

Python 2 casts integer division to an integer.

9 / 2 == 4

No need for correction.

In Python 3 we would need to cast the quotient explicitly...

n = int(len(sequence) / 2)

Caching the above makes for much simpler code.

Many users treat dividing by an arbitrary float as a cool shortcut. It is not. It works because Python treats the quotient as a float if one of the operands is a float. When we take a plain counting number, an integer, and fudge it over to a float we are not helping our reader

If anything would be expected to be a float, it would be the numerator in this case.

float(x[n -1) + x[n]) / 2

The reader can tell exactly what we have in mind.


#6

The convolution between integers and floats stems from my working through the lesson in my Python IDLE, which is Python 3 and the lesson itself which is Python 2. My code is NOT optimized for Python 2.

int((((len(sequence)) / 2.0) - .5))

For this line, I force the float division then subtract by 0.5 in order to get the actual index number for the sequence.

I have to do this because len() returns the number of items in a list instead of the index of the last item. So for sequence = [1, 2, 3, 4, 5], len() returns 5, then I divide by 2.0 to get 2.5, but the actual median item is at index 2. Remember this is all to find the index of the median value, which has to be in integer form, so I convert the forced float back to an integer.

If I didn't force the float division, then in Python 2 len(sequence)/2 would return 2 but in Python 3 it would return 2.5.

Optimized for Python 2, my code looks like this:

def median(sequence):
    sequence = sorted(sequence)
    if ((len(sequence) % 2) > 0):
        return sequence[len(sequence) / 2]
    else:
        return (sequence[len(sequence) / 2 - 1] + sequence[len(sequence) / 2]) / 2.0

I still have to divide by a float (or use float()) in the else: portion but it is overall much easier to read and understand.


#7

In Python 3, dividing by 2 will give a float, so there is no need to arbitrarily make it one.

n = int(len(sequence) / 2)

The above will give the same integer in both versions. And it's explicit.


#8

I also write in v3 first, then paste tested code into codecademy window; I've run into the same problem despite using int():

def median(somelist):
    if (len(somelist) % 2 == 1):                    # odd number of elements
        return sorted(somelist)[int(len(somelist) / 2)]
    else:
        lowmid = int(len(somelist) / 2) - 1         # lower middle index
        return (sorted(somelist)[lowmid]+sorted(somelist)[lowmid+1]) / 2

The lowmid value for [4, 5, 5, 4] should be int(4 / 2) - 1 = 2 - 1 = 1. This works in v3 but not here. Why?


#9

Consider the example posted above:

n = len(somelist)
m = int(n / 2)
s = sorted(somelist)

With these three things cached, we can write the conditional in simple, readable terms.

if n % 2: return s[m]
return float(s[m - 1] + s[m]) / 2

When code starts to look complicated and repetitive, it usually means a re-think is necessary. Caching is one way to reduce verbose repetition.


#10

While I appreciate the advice regarding code readability, I'm still puzzled why the float() is needed in v2:

def median(somelist):
    n = len(somelist)
    m = int(n / 2) - 1
    s = sorted(somelist)
    if n % 2: return s[m+1]
    return float(s[m] + s[m+1]) / 2

def median2(somelist):
    n = len(somelist)
    m = int(n / 2)
    s = sorted(somelist)
    if n % 2: return s[m]
    return float(s[m-1] + s[m]) / 2

Both functions work on v2 and v3 but fail to produce correct results on v2/here if float() is omitted. Why?


#11

Because Python 2 returns an integer from integer division, so if we want a float, we must declare it.


#12

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.