how to find the middle number in python - python

Given 3 numbers, I need to find which number lies between the two others.
ie,given 3,5,2
I need 3 to be returned.
I tried to implement this by going thru all three and using if else conditions to check if each is between the other two.But this seems a naive way to do this.Is there a better way?

Put them in a list, sort them, pick the middle one.

>>> x = [1,3,2]
>>> sorted(x)[len(x) // 2]
2

The fastest obvious way for three numbers
def mean3(a, b, c):
if a <= b <= c or c <= b <= a:
return b
elif b <= a <= c or c <= a <= b:
return a
else:
return c

What you want is the median. You can use this code below for any number of numbers:
import numpy
numbers = [3,5,2]
median = numpy.median(numbers)
for a custom solution you can visit this page.

You could do
numbers = [3, 5, 2]
sorted(numbers)[1]

This is a O(n) implementation of the median using cumulative distributions. It's faster than sorting, because sorting is O(ln(n)*n).
def median(data):
frequency_distribution = {i:0 for i in data}
for x in data:
frequency_distribution[x] =+ 1
cumulative_sum = 0
for i in data:
cumulative_sum += frequency_distribution[i]
if (cumulative_sum > int(len(data)*0.5)):
return i

Check this (Suppose list already sorted):
def median(list):
ceil_half_len = math.ceil((len(list)-1)/2) # get the ceil middle element's index
floor_half_len = math.floor((len(list)-1)/2) # get the floor middle element 's index'
return (list[ceil_half_len] + list[floor_half_len]) / 2

If it's just for 3 numbers. First find the max and the min numbers in list. Remove them, the remainder of list is the medium. If you don't want to use the "if-else" or "sorted()" that is.
def mid(a,b,c):
num = [a,b,c]
small, big = min(num), max(num)
num.remove(small)
num.remove(big)
return num[0] # return the remainder

Here is my attempt using a more pythonic version
def median(a):
sorted_a = sorted(a)
if len(a) % 2 == 0:
median = sum(sorted_a[(len(a)//2)-1:(len(a)//2)+1])/2.
else:
median = sorted_a[(len(a)-1)//2]
>>> x = [64630, 11735, 14216, 99233, 14470, 4978, 73429, 38120, 51135, 67060]
>>> median(x)
>>> 44627.5
>>> y = [1, 2, 3]
>>> median(y)
>>> 2

If you wish to avoid sorting, you can do:
def find_median(x):
return sum(x) - max(x) - min(x)

Related

How do i make a function that returns amount of indexes that are the same

I'm trying to make a number based Mastermind game. Trying to figure out a function that takes two lists as paramenters and if indexes in the lists are the same it should return the amount of indexes that are the same.
PS. hope you understand what i mean ;P
generated_number_as_list = [1,1,1,1]
guess_as_list = [1,2,1,2]
correct = right_inrightplace(guess_as_list, generated_number_as_list)
print(correct)
output >> 2
You can use zip to compare values with corresponding indexes and then sum True which will be cast to 1
print(sum(x==y for x,y in zip(generated_number_as_list, guess_as_list))) #2
I wrote it outside of a function. Just copy the for loop in your function and return the ans value as the output.
generated_number_as_list = [1,1,1,1]
guess_as_list = [1,2,1,2]
ans = 0
for i in range(len(generated_number_as_list)):
if guess_as_list[i] == generated_number_as_list[i]:
ans = ans + 1
print(ans)
You can try this also:
a=[1,1,1,1]
b=[1,2,1,2]
print(min(len([x for x in a if x in b]),len([x for x in b if x in a])))
You can use the sum and map with operator.eq:
def right_inrightplace(a, b):
return sum(map(eq, a, b))
Or without using additional libraries:
def right_inrightplace(a, b):
return sum(x == y for x, y in zip(a, b))
Just for fun here's a solution using recursion:
def right_inrightplace(a, b):
if len(a) == 0 or len(b) == 0:
return 0
current = 0
if a[0] == b[0]:
current = 1
return current+right_inrightplace(a[1:],b[1:])

maximum sum of a list

I am quite new to python. Just out of curiosity is there a simpler approach to find maximum sum of a list that includes both negative and positive integers?
for ex:
IN_1
l = [1,2,3]
OUT
6
IN_2
l = [1,-2,-3]
OUT
1
IN_3
l = [-1,-2,-3]
OUT
-1
If it was the case where IN_3 would return 0, then the approach was quite simple. Just removing all the negative elements and using sum.
l = [item for item in l if item >= 0]
sum(l)
The code worked pretty well for IN_1 and IN_2.
But I am having trouble in 3rd case IN_3 where it would necessarily take a number that is least negative and return it.
Try this:
l = input('').split()
s = sum([int(i) for i in l if int(i)>0]) or int(max(l, key=int))
You already outlined the approach so the implementation is simply:
def max_sum(l):
return sum(i for i in l if i > 0) or max(l)
print(max_sum([1,2,3]))
print(max_sum([1,-2,-3]))
print(max_sum([-1,-2,-3]))
This outputs:
6
1
-1
def getsum(l):
return sum({False:[max(l)]}.get(bool([i for i in l if i >0]),[i for i in l if i >0]))
print(getsum([1,2,3]))
print(getsum([1,-2,-3]))
print(getsum([-1,-2,-3]))
Output:
6
1
-1
l = [-1,-2,-3]
s = sum([i for i in l if i > 0])
s = s if s > 0 else max(l)
print(s)
It seems that you only have two cases to worry about:
The list contains only negative integers, i.e.
if max(list) < 0:
return max(list)
Some positive integers and potentially some negative integers (or none), i.e.
if max(list) > 0:
filter out negatives and return the sum of what is left
I have done from very basic and simple coding
My Answer as Follows:
l = [1,2,3]
m = [1,-2,-3]
j = [-1,-2,-3]
i = 0
for k in m:
i+=k
print(i)
I checked for all lists.

Determines the first integer that is evenly divisible by all other integers in a list of integers

def divisible(a):
d = 0
n = len(a)
i = 0
p = 0
while d == 0 and p < n and i < n:
if a[i] % a[p] != 0:
i = i + 1
p = 0
else:
p = p + 1
return d
a = [12, 4, 6]
r = divisible(a)
print(r)
Can anyone help me plsease? it is python 3.0 +. I can't solve this question, I don't know where I can put d into the function. like let d = a[i] if a[i] can evenly divisible by all other integers. The answer is 12 for this question, can anyone imporve my code plsease? Thank you!!
A short solution would be
def divisible(a):
for i in a:
if all(i%j==0 for j in a):
return i
return None
or a bit longer
def divisible(a):
for i in a:
found=True
for j in a:
if i%j: # everything that is not 0 is true
found=False
break
if found:
return i
return None
I have expended on my previous comment. We don't need to actually compute any multiples, since we expect it to already be in the list. The trick is just to take the max (or min, if negative numbers are allowed), and then validate.
But first, figure out how you are going to handle 0. It is divisible by all other integers, and cannot itself divide any integer, so I just return 0 in this example.
Also decide what you will do if you determine there is no correct answer. I returned None, but an exception may be more appropriate depending on the application.
def divisible(input_list):
# what to do with zero?
if 0 in input_list:
return 0
# get largest magnitude
candidate = max(map(abs, input_list))
# validate
if all([0 == candidate % x for x in input_list]):
return candidate
else:
# handle the case where there is no valid answer
return None
print divisible([12, 4, 6])
print divisible([-12, 4, 6, -3])
print divisible([12, 5, 7])
print divisible([12, 0, 4])
This has some similarity to janbrohl's answer, but that is an O(n**2) solution, checking every number against every other number. But we know the number we want will be the largest (in magnitude).
Proof by contradiction: Take two positive numbers [a, b] where a < b, and suppose that a is evenly divisible by b. But then a % b == 0. Since a < b, we know that a % b is a. Therefore a=0 or a=nb (for some n). But a < b, therefore a==0. (expand to signed integers on your own. The sign is largely irrelevant for determining divisibility.)
I think you're looking for the least common multiple algorithm, in python3 you could code it like this:
from fractions import gcd
from functools import reduce
def lcm(*args):
return reduce(lambda a, b: a * b // gcd(a, b), args)
print lcm(4, 6, 12)
But it seems you can't use any functions nor python builtin operators in your algorithm because educational purposes. Then one possible simple solution could just be like this:
def divisible(input_list):
result = None
if 0 in input_list:
return result
for i in input_list:
ok = True
for j in input_list:
if i!=j and i % j != 0:
ok = False
break
if ok:
return i
return result

How to see if the list contains consecutive numbers

I want to test if a list contains consecutive integers and no repetition of numbers.
For example, if I have
l = [1, 3, 5, 2, 4, 6]
It should return True.
How should I check if the list contains up to n consecutive numbers without modifying the original list?
I thought about copying the list and removing each number that appears in the original list and if the list is empty then it will return True.
Is there a better way to do this?
For the whole list, it should just be as simple as
sorted(l) == list(range(min(l), max(l)+1))
This preserves the original list, but making a copy (and then sorting) may be expensive if your list is particularly long.
Note that in Python 2 you could simply use the below because range returned a list object. In 3.x and higher the function has been changed to return a range object, so an explicit conversion to list is needed before comparing to sorted(l)
sorted(l) == range(min(l), max(l)+1))
To check if n entries are consecutive and non-repeating, it gets a little more complicated:
def check(n, l):
subs = [l[i:i+n] for i in range(len(l)) if len(l[i:i+n]) == n]
return any([(sorted(sub) in range(min(l), max(l)+1)) for sub in subs])
The first code removes duplicates but keeps order:
from itertools import groupby, count
l = [1,2,4,5,2,1,5,6,5,3,5,5]
def remove_duplicates(values):
output = []
seen = set()
for value in values:
if value not in seen:
output.append(value)
seen.add(value)
return output
l = remove_duplicates(l) # output = [1, 2, 4, 5, 6, 3]
The next set is to identify which ones are in order, taken from here:
def as_range(iterable):
l = list(iterable)
if len(l) > 1:
return '{0}-{1}'.format(l[0], l[-1])
else:
return '{0}'.format(l[0])
l = ','.join(as_range(g) for _, g in groupby(l, key=lambda n, c=count(): n-next(c)))
l outputs as: 1-2,4-6,3
You can customize the functions depending on your output.
We can use known mathematics formula for checking consecutiveness,
Assuming min number always start from 1
sum of consecutive n numbers 1...n = n * (n+1) /2
def check_is_consecutive(l):
maximum = max(l)
if sum(l) == maximum * (maximum+1) /2 :
return True
return False
Once you verify that the list has no duplicates, just compute the sum of the integers between min(l) and max(l):
def check(l):
total = 0
minimum = float('+inf')
maximum = float('-inf')
seen = set()
for n in l:
if n in seen:
return False
seen.add(n)
if n < minimum:
minimum = n
if n > maximum:
maximum = n
total += n
if 2 * total != maximum * (maximum + 1) - minimum * (minimum - 1):
return False
return True
import numpy as np
import pandas as pd
(sum(np.diff(sorted(l)) == 1) >= n) & (all(pd.Series(l).value_counts() == 1))
We test both conditions, first by finding the iterative difference of the sorted list np.diff(sorted(l)) we can test if there are n consecutive integers. Lastly, we test if the value_counts() are all 1, indicating no repeats.
I split your query into two parts part A "list contains up to n consecutive numbers" this is the first line if len(l) != len(set(l)):
And part b, splits the list into possible shorter lists and checks if they are consecutive.
def example (l, n):
if len(l) != len(set(l)): # part a
return False
for i in range(0, len(l)-n+1): # part b
if l[i:i+3] == sorted(l[i:i+3]):
return True
return False
l = [1, 3, 5, 2, 4, 6]
print example(l, 3)
def solution(A):
counter = [0]*len(A)
limit = len(A)
for element in A:
if not 1 <= element <= limit:
return False
else:
if counter[element-1] != 0:
return False
else:
counter[element-1] = 1
return True
The input to this function is your list.This function returns False if the numbers are repeated.
The below code works even if the list does not start with 1.
def check_is_consecutive(l):
"""
sorts the list and
checks if the elements in the list are consecutive
This function does not handle any exceptions.
returns true if the list contains consecutive numbers, else False
"""
l = list(filter(None,l))
l = sorted(l)
if len(l) > 1:
maximum = l[-1]
minimum = l[0] - 1
if minimum == 0:
if sum(l) == (maximum * (maximum+1) /2):
return True
else:
return False
else:
if sum(l) == (maximum * (maximum+1) /2) - (minimum * (minimum+1) /2) :
return True
else:
return False
else:
return True
1.
l.sort()
2.
for i in range(0,len(l)-1)))
print(all((l[i+1]-l[i]==1)
list must be sorted!
lst = [9,10,11,12,13,14,15,16]
final = True if len( [ True for x in lst[:-1] for y in lst[1:] if x + 1 == y ] ) == len(lst[1:]) else False
i don't know how efficient this is but it should do the trick.
With sorting
In Python 3, I use this simple solution:
def check(lst):
lst = sorted(lst)
if lst:
return lst == list(range(lst[0], lst[-1] + 1))
else:
return True
Note that, after sorting the list, its minimum and maximum come for free as the first (lst[0]) and the last (lst[-1]) elements.
I'm returning True in case the argument is empty, but this decision is arbitrary. Choose whatever fits best your use case.
In this solution, we first sort the argument and then compare it with another list that we know that is consecutive and has no repetitions.
Without sorting
In one of the answers, the OP commented asking if it would be possible to do the same without sorting the list. This is interesting, and this is my solution:
def check(lst):
if lst:
r = range(min(lst), max(lst) + 1) # *r* is our reference
return (
len(lst) == len(r)
and all(map(lst.__contains__, r))
# alternative: all(x in lst for x in r)
# test if every element of the reference *r* is in *lst*
)
else:
return True
In this solution, we build a reference range r that is a consecutive (and thus non-repeating) sequence of ints. With this, our test is simple: first we check that lst has the correct number of elements (not more, which would indicate repetitions, nor less, which indicates gaps) by comparing it with the reference. Then we check that every element in our reference is also in lst (this is what all(map(lst.__contains__, r)) is doing: it iterates over r and tests if all of its elements are in lts).
l = [1, 3, 5, 2, 4, 6]
from itertools import chain
def check_if_consecutive_and_no_duplicates(my_list=None):
return all(
list(
chain.from_iterable(
[
[a + 1 in sorted(my_list) for a in sorted(my_list)[:-1]],
[sorted(my_list)[-2] + 1 in my_list],
[len(my_list) == len(set(my_list))],
]
)
)
)
Add 1 to any number in the list except for the last number(6) and check if the result is in the list. For the last number (6) which is the greatest one, pick the number before it(5) and add 1 and check if the result(6) is in the list.
Here is a really short easy solution without having to use any imports:
range = range(10)
L = [1,3,5,2,4,6]
L = sorted(L, key = lambda L:L)
range[(L[0]):(len(L)+L[0])] == L
>>True
This works for numerical lists of any length and detects duplicates.
Basically, you are creating a range your list could potentially be in, editing that range to match your list's criteria (length, starting value) and making a snapshot comparison. I came up with this for a card game I am coding where I need to detect straights/runs in a hand and it seems to work pretty well.

Joining elements in a list without the join command

I need to join the elements in a list without using the join command, so if for example I have the list:
[12,4,15,11]
The output should be:
1241511
Here is my code so far:
def lists(list1):
answer = 0
h = len(list1)
while list1 != []:
answer = answer + list1[0] * 10 ** h
h = h - 1
list1.pop(0)
print(answer)
But, in the end, the answer ends up being 125610 which is clearly wrong.
I think the logic is OK, but I can't find the problem?
If you just want to print the number rather than return an actual int:
>>> a = [12,4,15,11]
>>> print(*a, sep='')
1241511
You could just convert each element to a string, add them, and then convert back to an int:
def lists(list1):
answer=''
for number in list1:
answer+=str(number)
print(int(answer))
lists([12,4,15,11])
>>>
1241511
s = ""
for x in map(str, x):
s += x
print(s)
1241511
There can be few more options like
Option1
>>> lst=[12,4,15,11]
>>> str(lst).translate(None, '[,] ')
'1241511'
Option 2
>>> join = lambda e: str(e[0]) + join(e[1:]) if e else ""
>>> join(lst)
'1241511'
Option 3
>>> ("{}"*len(lst)).format(*lst)
'1241511'
Option 4
>>> reduce(lambda a,b:a+b,map(str,lst))
'1241511'
a numeric solution, using your code
import math
def numdig(n):
#only positive numbers
if n > 0:
return int(math.log10(n))+1
else:
return 1
def lists(list1):
answer = 0
h = 0
while list1 != []:
answer = answer * 10 ** h + list1[0]
list1.pop(0)
if list1 != []:
h = numdig(list1[0])
print(answer)
lists([12,4,15,11])
You may try map and reduce with lambda like this:
def without_join(alist):
try:
return int(reduce(lambda a,b: a + b, map(str, alist)))
except ValueError, error:
print error
return None
print without_join([12,4,15,11])
Here's an entirely numerical solution, playing off of your notion of messing with powers of 10. You were on the right track, but your implementation assumed all values were 1 digit long.
import math
def lists(list1):
b = 0
foo = 0
for item in reversed(list1):
b += item*(10**foo)
foo += int(math.floor(math.log10(item))) + 1
return b
a = [12, 4, 15, 11]
print lists(a)
This returns 1241511, as requested.
All I'm doing here is looping through the list in reverse order and keeping track of how many digits to the left I need to shift each value. This allows integers with an arbitrary number of digits.
list_name_of_program = [a,b,c,d,e,f]
program = ""
for pro in list_name_of_program:
program += str(pro)
program += "," # you can use seprator a space " " or different
print(program[:-1])
Output:
'a,b,c,d,e,f'

Categories