Python: Median of a list of numbers - python

When I run my program on PyScripter, I get the expected median of 4.5. But running the same code on Ideone as here or on codeacademy returns 4. Any idea why the different results? Thanks.
#Create a function that returns the median of a list of numbers
def median(list_of_numbers):
#Make a copy of list_of_numbers and sort the new list
lst = list_of_numbers
lst = sorted(lst)
#Get the length of list and use it to index through the list
lst_length = len(lst)
index = int(lst_length/2)
#If length if even, average the two middle numbers
if lst_length%2==0:
a= lst[index-1]
b = lst[index]
result = (a+b)/2
#If length is odd, return the middle number
else:
result = lst[index]
return result
print (median([4, 5, 5, 4]))
My PyScripter version: * Python 3.3.5 (v3.3.5:62cf4e77f785, Mar 9 2014, 10:37:12) [MSC v.1600 32 bit (Intel)] on win32. *

For Python 2.x you will need to replace both occurrences of 2 by 2. in order to enforce floating point division.
Your link to ideone is Python 2.x and apparently so is your codeacademy interpreter.

import statistics as s
def mid(data):
return(int(s.median(data)))
middle = mid([3,4,6,3,12,6,45,32,78])
print(middle)
I'd use the statistics module. If you want your output to be an integer or a float, just cast it (float() or int() respectively).

Related

Converting from Float to Int changed the output

I defined a simple sqrt function to calculate a square root of a given number.
def sqrt(n):
low = 0
up = n
for i in range(50):
mid = float(low+up)/2
if pow(mid,2) < n:
low = mid
elif pow(mid,2) > n:
up = mid
else:
break
return mid
When I do:
print(sqrt(9))
I get 3.0 as the output. However when I do:
print(int(sqrt(9))) I get 2.
Could somebody please help me understand why this is happening?
Thank you.
Actually, sqrt(9) returns 2.9999999999999973 [1], at least in Python version 3.5 (and perhaps all versions 3.x?). And int returns only the integer component of the number. That's why you get 2 as the result, as the integer component of 2.9999999999999973 is indeed 2.
If you want to round the result to the nearest integer, you can do round(sqrt(9)) which produces 3.
[1] To understand why this happens and how to fix this issue, you can refer to this post.
It is because of rounding. Your method definition actually computes the sqrt(9) to be 2.9999999999999973. However the rounding is not applied to casting, therefore the decimal is lost in the casting of int(2.9999999999999973).
When you print directly, python applies rounding which brings this value up to 3.
Python 2.7 output:
Python 2.7.17 (v2.7.17:c2f86d86e6, Oct 19 2019, 21:01:17) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> def sqrt(n):
... low = 0
... up = n
... for i in range(50):
... mid = float(low+up)/2
... if pow(mid,2) < n:
... low = mid
... elif pow(mid,2) > n:
... up = mid
... else:
... break
... return mid
...
>>> sqrt(9)
2.9999999999999973
>>> print(sqrt(9))
3.0
>>> print(int(sqrt(9)))
2
>>>
If you want to get converted into int you can use the following:
print(int(round(sqrt(9))))

Same code in Python 3.x and Python 2.x gives different results

I've built a function to calculate median (as the name indicates).
The function receives a list of ints, for instances [4,5,5,4] and should output 4,5.
The code:
def median(lst):
lst.sort()
a=int(len(lst)/2)
if len(lst) % 2 == 0:
med=float((lst[a]+lst[a-1])/2)
else:
med=lst[a]
return med
print(median([4,5,5,4]))
This works fine when using Python 3.x but not in Python 2.x. What am i doing wrong?
The problem is you are assuming the division operator is the same in both Python 2 and 3. Instead (adapted from mhlester):
in Python 2, / is integer division (int inputs);
in Python 3, / is float division;
in Python 2 and 3, // is integer division.
In order to achieve what you are looking for, there's different workarounds. For instances:
You can make sure to have at least one operand of your division in float. Eg:
def median(lst):
lst.sort()
a=int(len(lst)/float(2))
if len(lst) % 2 == 0:
med=float((lst[a]+lst[a-1])/float(2))
else:
med=lst[a]
return med
print(median([4,5,5,4]))
You can use the import from __future__ import division (this needs to be done before any other imports). Eg:
from __future__ import division
def median(lst):
lst.sort()
a=int(len(lst)/2)
if len(lst) % 2 == 0:
med=float((lst[a]+lst[a-1])/2)
else:
med=lst[a]
return med
print(median([4,5,5,4]))

possible Python integer overflow error

Below is my code that I'm trying to run to solve for a maximum prioritized product problem i.e. return a maximum value for a product of two numbers in a list. My issue is that the product that is being computed is incorrect when the numbers in the input list are large. I was of the opinion that there will be no integer overflow in error and resulting product will be automatically long but that is not happening evidently as my multiplication is returning some kind of garbage.
#"python2"
# -*- coding: utf-8 -*-
"""
Created on Tue Jun 28 17:12:38 2016
#author: pvatsa
"""
import numpy as np
n = int(raw_input())
alist = np.random.randint(100000, size = n)
print alist
assert(len(alist) == n)
alist = sorted(alist)
print alist
max_no = max(alist)
second_largest_no = alist[n-2]
print max_no*second_largest_no
#print long(product)
#print type(product)
Using np.random.randint will create an array of 32 bits integers:
>>> alist = np.random.randint(100000, size = n)
>>> alist.dtype
dtype('int32')
Sorting it will preserve that type, creating a list of numpy.int32 objects instead of converting them back to Python (overflow-safe) integers:
>>> foo = sorted(alist)
>>> type(foo[-1])
<type 'numpy.int32'>
As such, the multiplication can overflow: you can solve it by either:
Casting your numbers back to Python numbers
Having an array of longs in the first place
The first case is simply a matter of converting values of interest:
>>> foo[-1] * foo[-2]
1386578402
>>> int(foo[-1]) * int(foo[-2])
9976512994L
The second can be done by calling randint with dtype=np.int64 (for numpy >= 1.11) or converting the array afterwards:
>>> llist = np.array(alist, dtype=np.int64)
>>> llist.sort()
>>> np.prod(llist[-2:])
9987503750

Bitwise 'AND' operator and its evaluation in a code

I've came across bitwise operators, and they really seem odd to me. Just wanted to get clarifications on two questions that I don't fully understand. The first piece of code is:
x = raw_input('Enter a digit: ')
print 'x is %s' % ('Even', 'Odd')[x & 1]
The question is the following - How does it exactly evaluates to 'Even' if I enter an even digit, and how does it pick the first element in parenthesis after evaluation?
On top of the that, can you please explain this piece of code:
if a[i-1] & 1 and a[i] & 1:
do some stuff
Thank you all
Bitwise operations work on binary representations of your integer numbers.
if a[i-1] & 1 and a[i] & 1:
do some stuff
Checks if both the entries at positions i and i-1 are odd numbers. This is realized by checking if the rightmost (least significant) bit of the numbers is 1. Take 42 and 23 as an example:
>>> bin(42)
'0b101010'
>>> bin(23)
'0b10111'
>>> bin(1)
'0b1'
Now you can apply a bitwise AND with one to both numbers. This operator returns a binary number which has a 1 on those positions, where the first AND the second input number have a 1-bit (and only there). Shorter numbers are padded with leading zeros:
binary decimal
101010 = 42
& 000001 = 1
--------
000000 = 0
10111 = 23
& 00001 = 1
--------
00001 = 1
So basically this is another way of doing:
if a[i-1]%2 == 1 and a[i]%2 == 1:
do some stuff
Your code is broken, since it applies &, the bitwise AND, to x which holds a string. Here's what I got when I tried your code in Python 2.x:
Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> x=raw_input("enter a digit")
enter a digit4
>>> x
'4'
>>> x&1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'str' and 'int'
You need to parse it as integer:
print "x is %s" % ("even", "odd")[int(x) & 1]
This works by "masking" out the right-most bit of x using & 1. This will be set if the number is odd, and clear if it's even. The resulting number (0 or 1) is used to index into the pair ("even", "odd").

How to convert an integer to variable length byte string?

I want to convert an integer (int or long) a big-endian byte string. The byte string has to be of variable length, so that only the minimum number of bytes are used (the total length length of the preceding data is known, so the variable length can be inferred).
My current solution is
import bitstring
bitstring.BitString(hex=hex(456)).tobytes()
Which obviously depends on the endianness of the machine and gives false results, because 0 bits are append and no prepended.
Does any one know a way to do this without making any assumption about the length or endianess of an int?
Something like this. Untested (until next edit). For Python 2.x. Assumes n > 0.
tmp = []
while n:
n, d = divmod(n, 256)
tmp.append(chr(d))
result = ''.join(tmp[::-1])
Edit: tested.
If you don't read manuals but like bitbashing, instead of the divmod caper, try this:
d = n & 0xFF; n >>= 8
Edit 2: If your numbers are relatively small, the following may be faster:
result = ''
while n:
result = chr(n & 0xFF) + result
n >>= 8
Edit 3: The second method doesn't assume that the int is already bigendian. Here's what happens in a notoriously littleendian environment:
Python 2.7 (r27:82525, Jul 4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> n = 65539
>>> result = ''
>>> while n:
... result = chr(n & 0xFF) + result
... n >>= 8
...
>>> result
'\x01\x00\x03'
>>> import sys; sys.byteorder
'little'
>>>
A solution using struct and itertools:
>>> import itertools, struct
>>> "".join(itertools.dropwhile(lambda c: not(ord(c)), struct.pack(">i", 456))) or chr(0)
'\x01\xc8'
We can drop itertools by using a simple string strip:
>>> struct.pack(">i", 456).lstrip(chr(0)) or chr(0)
'\x01\xc8'
Or even drop struct using a recursive function:
def to_bytes(n):
return ([chr(n & 255)] + to_bytes(n >> 8) if n > 0 else [])
"".join(reversed(to_bytes(456))) or chr(0)
If you're using Python 2.7 or later then you can use the bit_length method to round the length up to the next byte:
>>> i = 456
>>> bitstring.BitString(uint=i, length=(i.bit_length()+7)/8*8).bytes
'\x01\xc8'
otherwise you can just test for whole-byteness and pad with a zero nibble at the start if needed:
>>> s = bitstring.BitString(hex=hex(i))
>>> ('0x0' + s if s.len%8 else s).bytes
'\x01\xc8'
I reformulated John Machins second answer in one line for use on my server:
def bytestring(n):
return ''.join([chr((n>>(i*8))&0xFF) for i in range(n.bit_length()/8,-1,-1)])
I have found that the second method, using bit-shifting, was faster for both large and small numbers, and not just small numbers.

Categories