How can I find the minimum in Python? - python

This function finds the maximum and minimum values.
n=int(input())
array=list(map(int,input().split))
for i in range(n):
max=array[0]
if i>0:
if max<array[i]:
max=array[i]
for i in range(n):
min=array[0]
if i>0:
if min>array[i]:
min=array[i]
print(max,end='')
print( min)
The maximum value comes out normally, but the minimum value comes out as the first array value. I can't find what is wrong.

The maximum value comes out normally
I think it does only because either your first or last value is the max of the sequence. Because you completely reset both min and max on each iteration. So the entire loop is useless, any iteration but the last has no effect.
The initialisation should be outside the loop, not inside of it:
max=array[0]
for i in range(n):
if i>0:
if max<array[i]:
max=array[i]
min=array[0]
for i in range(n):
if i>0:
if min>array[i]:
min=array[i]
At which point the check on the index is clearly unnecessary: either eat the unnecessary comparison of array[0] to array[0] (it's not harmful per-se), or just skip the index when iterating:
max=array[0]
for i in range(1, n):
if max<array[i]:
max=array[i]
min=array[0]
for i in range(1, n):
if min>array[i]:
min=array[i]
In essence you've written a very complicated version of:
if array[0] < array[-1]:
max = array[-1]
else:
max = array[0]
if array[0] > array[-1]:
min = array[-1]
else:
min = array[0]
Now for further improvements, under the assumption that you're trying to learn we'll ignore that min and max are already built-in functions and thus the entire thing is redundant (although you should not name your own variables the same as builtins, as that creates confusion):
n is useless, because it's not checked against array and array has its own length, n can only trigger unnecessary errors if it exceeds len(array), or skip item if it's smaller than len(array). n might be useful if e.g. the input was gathered in a loop of validated input() call, which is not the case.
Good error handling would probably check that the length of the array is at least 1, otherwise the script will blow up (although it would also need to check that individual input values are valid before converting to integers so...)
You can extract min and max in the same loop, no need to loop twice (probably not very important in this case).
But Python also has good support for iterators, so you should avoid explicit indexing when not necessary, which it is not here.
And my take, still within the realm of trying to learn, would be:
array=list(map(int,input().split))
low = high = array[0]
for candidate in array[1:]:
if candidate > high:
high = candidate
if candidate < low:
low = candidate
print(f"{low} ... {high}")
An other fun alternative is to sort the array and take the first and last elements of the now-sorted array:
array=list(map(int,input().split))
low, *_, high = sorted(array)
print(f"{low} ... {high}")
although it has the drawback that it only works on array of length 2+ where the original works on "singleton" arrays.

Use the min and max keyword from python for this.
E.g.
my_list = [0, -5, 3, 1, 10]
min_value = min(my_list)
max_value = max(my_list)
print(f'Min value: {min_value}, max value: {max_value}')

Do you just want the min and max of a list of integers a user inputs? Use the build-in functions of python for that:
list_of_user_input = []
n_input = int(input("How many variables do you want to enter: "))
for i in range(0, n_input):
number = int(input(f"Enter variable {i + 1}: "))
list_of_user_input.append(number)
print(f"The min of your list is {min(list_of_user_input)}")
print(f"The max of your list is {max(list_of_user_input)}")

Related

Find the indices of the two largest and two smallest values in a matrix in python

I am attempting to find the indices of the two smallest and the two largest values in python:
I have
import sklearn
euclidean_matrix=sklearn.metrics.pairwise_distances(H10.T,metric='euclidean')
max_index =np.where(euclidean_matrix==np.max(euclidean_matrix[np.nonzero(euclidean_matrix)]))
min_index=np.where(euclidean_matrix==np.min(euclidean_matrix[np.nonzero(euclidean_matrix)]))
min_index
max_index
I get the following output
(array([158, 272]), array([272, 158]))
(array([ 31, 150]), array([150, 31]))
the above code only returns the indices of the absolute smallest and the absolute largest values of the matrix, I would like to find the indices of the next smallest value and the indices of the next largest value. How can I do this? Ideally I would like to return the indices of the 2 largest values of the matrix and the indices of the two smallest values of the matrix. How can I do this?
I can think of a couple ways of doing this. Some of these depend on how much data you need to search through.
A couple of caveats: You will have to decide what to do when there are 1, 2, 3 elements only Or if all the same value, do you want min, max, etc to be identical? What if there are multiple items in max or min or min2, max2? which should be selected?
run min then remove that element run min on the rest. run max then remove that element and run on the rest (note that this is on the original and not the one with min removed). This is the least efficient method since it requires searching 4 times and copying twice. (Actually 8 times because we find the min/max then find the index.) Something like the in the pseudo code.
PSEUDO CODE:
max_index = np.where(euclidean_matrix==np.max(euclidean_matrix[np.nonzero(euclidean_matrix)]))
tmp_euclidean_matrix = euclidean_matrix #make sure this is a deepcopy
tmp_euclidean_matrix.remove(max_index) #syntax might not be right?
max_index2 = np.where(tmp_euclidean_matrix==np.max(tmp_euclidean_matrix[np.nonzero(tmp_euclidean_matrix)]))
min_index = np.where(euclidean_matrix==np.min(euclidean_matrix[np.nonzero(euclidean_matrix)]))
tmp_euclidean_matrix = euclidean_matrix #make sure this is a deepcopy
tmp_euclidean_matrix.remove(min_index) #syntax might not be right?
min_index2 = np.where(tmp_euclidean_matrix==np.min(tmp_euclidean_matrix[np.nonzero(tmp_euclidean_matrix)]))
Sort the data (if you need it sorted anyway this is a good option) then just grab two smallest and largest. This isn't great unless you needed it sorted anyway because of many copies and comparisons to sort.
PSEUDO CODE:
euclidean_matrix.sort()
min_index = 0
min_index2 = 1
max_index = len(euclidean_matrix) - 1
max_index2 = max_index - 1
Best option would be to roll your own search function to run on the data, this would be most efficient because you would go through the data only once to collect them.
This is just a simple iterative approach, other algorithms may be more efficient. You will want to validate this works though.
PSEUDO CODE:
def minmax2(array):
""" returns (minimum, second minimum, second maximum, maximum)
"""
if len(array) == 0:
raise Exception('Empty List')
elif len(array) == 1:
#special case only 1 element need at least 2 to have different
minimum = 0
minimum2 = 0
maximum2 = 0
maximum = 0
else:
minimum = 0
minimum2 = 1
maximum2 = 1
maximum = 0
for i in range(1, len(array)):
if array[i] <= array[minimum]:
# a new minimum (or tie) will shift the other minimum
minimum2 = minimum
minimum = i
elif array[i] < array[minimum2]:
minimum2 = i
elif array[i] >= array[maximum]:
# a new maximum (or tie) will shift the second maximum
maximum2 = maximum
maximum = i
elif array[i] > array[maximum2]:
maximum2 = i
return (minimum, minimum2, maximum2, maximum)
edit: Added pseudo code

recursion vs iteration time complexity

Could anyone explain exactly what's happening under the hood to make the recursive approach in the following problem much faster and efficient in terms of time complexity?
The problem: Write a program that would take an array of integers as input and return the largest three numbers sorted in an array, without sorting the original (input) array.
For example:
Input: [22, 5, 3, 1, 8, 2]
Output: [5, 8, 22]
Even though we can simply sort the original array and return the last three elements, that would take at least O(nlog(n)) time as the fastest sorting algorithm would do just that. So the challenge is to perform better and complete the task in O(n) time.
So I was able to come up with a recursive solution:
def findThreeLargestNumbers(array, largest=[]):
if len(largest) == 3:
return largest
max = array[0]
for i in array:
if i > max:
max = i
array.remove(max)
largest.insert(0, max)
return findThreeLargestNumbers(array, largest)
In which I kept finding the largest number, removing it from the original array, appending it to my empty array, and recursively calling the function again until there are three elements in my array.
However, when I looked at the suggested iterative method, I composed this code:
def findThreeLargestNumbers(array):
sortedLargest = [None, None, None]
for num in array:
check(num, sortedLargest)
return sortedLargest
def check(num, sortedLargest):
for i in reversed(range(len(sortedLargest))):
if sortedLargest[i] is None:
sortedLargest[i] = num
return
if num > sortedLargest[i]:
shift(sortedLargest, i, num)
return
def shift(array, idx, element):
if idx == 0:
array[0] = element
return array
array[0] = array[1]
array[idx-1] = array[idx]
array[idx] = element
return array
Both codes passed successfully all the tests and I was convinced that the iterative approach is faster (even though not as clean..). However, I imported the time module and put the codes to the test by providing an array of one million random integers and calculating how long each solution would take to return back the sorted array of the largest three numbers.
The recursive approach was way much faster (about 9 times faster) than the iterative approach!
Why is that? Even though the recursive approach is traversing the huge array three times and, on top of that, every time it removes an element (which takes O(n) time as all other 999 elements would need to be shifted in the memory), whereas the iterative approach is traversing the input array only once and yes making some operations at every iteration but with a very negligible array of size 3 that wouldn't even take time at all!
I really want to be able to judge and pick the most efficient algorithm for any given problem so any explanation would tremendously help.
Advice for optimization.
Avoid function calls. Avoid creating temporary garbage. Avoid extra comparisons. Have logic that looks at elements as little as possible. Walk through how your code works by hand and look at how many steps it takes.
Your recursive code makes only 3 function calls, and as pointed out elsewhere does an average of 1.5 comparisons per call. (1 while looking for the min, 0.5 while figuring out where to remove the element.)
Your iterative code makes lots of comparisons per element, calls excess functions, and makes calls to things like sorted that create/destroy junk.
Now compare with this iterative solution:
def find_largest(array, limit=3):
if len(array) <= limit:
# Special logic not needed.
return sorted(array)
else:
# Initialize the answer to values that will be replaced.
min_val = min(array[0:limit])
answer = [min_val for _ in range(limit)]
# Now scan for smallest.
for i in array:
if answer[0] < i:
# Sift elements down until we find the right spot.
j = 1
while j < limit and answer[j] < i:
answer[j-1] = answer[j]
j = j+1
# Now insert.
answer[j-1] = i
return answer
There are no function calls. It is possible that you can make up to 6 comparisons per element (verify that answer[0] < i, verify that (j=1) < 3, verify that answer[1] < i, verify that (j=2) < 3, verify that answer[2] < i, then find that (j=3) < 3 is not true). You will hit that worst case if array is sorted. But most of the time you only do the first comparison then move to the next element. No muss, no fuss.
How does it benchmark?
Note that if you wanted the smallest 100 elements, then you'd find it worthwhile to use a smarter data structure such as a heap to avoid the bubble sort.
I am not really confortable with python, but I have a different approach to the problem for what it's worth.
As far as I saw, all solutions posted are O(NM) where N is the length of the array and M the length of the largest elements array.
Because of your specific situation whereN >> M you could say it's O(N), but the longest the inputs the more it will be O(NM)
I agree with #zvone that it seems you have more steps in the iterative solution, which sounds like an valid explanation to your different computing speeds.
Back to my proposal, implements binary search O(N*logM) with recursion:
import math
def binarySearch(arr, target, origin = 0):
"""
Recursive binary search
Args:
arr (list): List of numbers to search in
target (int): Number to search with
Returns:
int: index + 1 from inmmediate lower element to target in arr or -1 if already present or lower than the lowest in arr
"""
half = math.floor((len(arr) - 1) / 2);
if target > arr[-1]:
return origin + len(arr)
if len(arr) == 1 or target < arr[0]:
return -1
if arr[half] < target and arr[half+1] > target:
return origin + half + 1
if arr[half] == target or arr[half+1] == target:
return -1
if arr[half] < target:
return binarySearch(arr[half:], target, origin + half)
if arr[half] > target:
return binarySearch(arr[:half + 1], target, origin)
def findLargestNumbers(array, limit = 3, result = []):
"""
Recursive linear search of the largest values in an array
Args:
array (list): Array of numbers to search in
limit (int): Length of array returned. Default: 3
Returns:
list: Array of max values with length as limit
"""
if len(result) == 0:
result = [float('-inf')] * limit
if len(array) < 1:
return result
val = array[-1]
foundIndex = binarySearch(result, val)
if foundIndex != -1:
result.insert(foundIndex, val)
return findLargestNumbers(array[:-1],limit, result[1:])
return findLargestNumbers(array[:-1], limit,result)
It is quite flexible and might be inspiration for a more elaborated answer.
The recursive solution
The recursive function goes through the list 3 times to fins the largest number and removes the largest number from the list 3 times.
for i in array:
if i > max:
...
and
array.remove(max)
So, you have 3×N comparisons, plus 3x removal. I guess the removal is optimized in C, but there is again about 3×(N/2) comparisons to find the item to be removed.
So, a total of approximately 4.5 × N comparisons.
The other solution
The other solution goes through the list only once, but each time it compares to the three elements in sortedLargest:
for i in reversed(range(len(sortedLargest))):
...
and almost each time it sorts the sortedLargest with these three assignments:
array[0] = array[1]
array[idx-1] = array[idx]
array[idx] = element
So, you are N times:
calling check
creating and reversing a range(3)
accessing sortedLargest[i]
comparing num > sortedLargest[i]
calling shift
comparing idx == 0
and about 2×N/3 times doing:
array[0] = array[1]
array[idx-1] = array[idx]
array[idx] = element
and N/3 times array[0] = element
It is difficult to count, but that is much more than 4.5×N comparisons.

Better python logic that prevent time out when comparing arrays in nested loops

I was attempting to solve a programing challenge and the program i wrote solved the small test data correctly for this question. But When they run it against the larger datasets, my program timed out on some of the occasions . I am mostly a self taught programmer, if there is a better algorithm/implementation than my logic can you guys tell me.thanks.
Question
Given an array of integers, a, return the maximum difference of any
pair of numbers such that the larger integer in the pair occurs at a
higher index (in the array) than the smaller integer. Return -1 if you
cannot find a pair that satisfies this condition.
My Python Function
def maxDifference( a):
diff=0
find=0
leng = len(a)
for x in range(0,leng-1):
for y in range(x+1,leng):
if(a[y]-a[x]>=diff):
diff=a[y]-a[x]
find=1
if find==1:
return diff
else:
return -1
Constraints:
1 <= N <= 1,000,000
-1,000,000 <= a[i] <= 1,000,000 i belongs to [1,N]
Sample Input:
Array { 2,3,10,2,4,8,1}
Sample Output:
8
Well... since you don't care for anything else than finding the highest number following the lowest number, provided that difference is the highest so far, there's no reason to do several passes or using max() over a slice of the array:
def f1(a):
smallest = a[0]
result = 0
for b in a:
if b < smallest:
smallest = b
if b - smallest > result:
result = b - smallest
return result if result > 0 else -1
Thanks #Matthew for the testing code :)
This is very fast even on large sets:
The maximum difference is 99613 99613 99613
Time taken by Sojan's method: 0.0480000972748
Time taken by #Matthews's method: 0.0130000114441
Time taken by #GCord's method: 0.000999927520752
The reason your program takes too long is that your nested loop inherently means quadratic time.
The outer loop goes through N-1 indices. The inner loop goes through a different number of indices each time, but the average is obviously (N-1)/2 rounded up. So, the total number of times through the inner loop is (N-1) * (N-1)/2, which is O(N^2). For the maximum N=1000000, that means 499999000001 iterations. That's going to take a long time.
The trick is to find a way to do this in linear time.
Here's one solution (as a vague description, rather than actual code, so someone can't just copy and paste it when they face the same test as you):
Make a list of the smallest value before each index. Each one is just min(smallest_values[-1], arr[i]), and obviously you can do this in N steps.
Make a list of the largest value after each index. The simplest way to do this is to reverse the list, do the exact same loop as above (but with max instead of min), then reverse again. (Reversing a list takes N steps, of course.)
Now, for each element in the list, instead of comparing to every other element, you just have to compare to smallest_values[i] and largest_values[i]. Since you're only doing 2 comparisons for each of the N values, this takes 2N time.
So, even being lazy and naive, that's a total of N + 3N + 2N steps, which is O(N). If N=1000000, that means 6000000 steps, which is a whole lot faster than 499999000001.
You can obviously see how to remove the two reverses, and how to skip the first and last comparisons. If you're smart, you can see how to take the whole largest_values out of the equation entirely. Ultimately, I think you can get it down to 2N - 3 steps, or 1999997. But that's all just a small constant improvement; nowhere near as important as fixing the basic algorithmic problem. You'd probably get a bigger improvement than 3x (maybe 20x), for less work, by just running the naive code in PyPy instead of CPython, or by converting to NumPy—but you're not going to get the 83333x improvement in any way other than changing the algorithm.
Here's a linear time solution. It keeps a track of the minimum value before each index of the list. These minimum values are stored in a list min_lst. Finally, the difference between corresponding elements of the original and the min list is calculated into another list of differences by zipping the two. The maximum value in this differences list should be the required answer.
def get_max_diff(lst):
min_lst = []
running_min = lst[0]
for item in lst:
if item < running_min:
running_min = item
min_lst.append(running_min)
val = max(x-y for (x, y) in zip(lst, min_lst))
if not val:
return -1
return val
>>> get_max_diff([5, 6, 2, 12, 8, 15])
13
>>> get_max_diff([2, 3, 10, 2, 4, 8, 1])
8
>>> get_max_diff([5, 4, 3, 2, 1])
-1
Well, I figure since someone in the same problem can copy your code and run with that, I won't lose any sleep over them copying some more optimized code:
import time
import random
def max_difference1(a):
# your function
def max_difference2(a):
diff = 0
for i in range(0, len(a)-1):
curr_diff = max(a[i+1:]) - a[i]
diff = max(curr_diff, diff)
return diff if diff != 0 else -1
my_randoms = random.sample(range(100000), 1000)
t01 = time.time()
max_dif1 = max_difference1(my_randoms)
dt1 = time.time() - t01
t02 = time.time()
max_dif2 = max_difference2(my_randoms)
dt2 = time.time() - t02
print("The maximum difference is", max_dif1)
print("Time taken by your method:", dt1)
print("Time taken by my method:", dt2)
print("My method is", dt1/dt2, "times faster.")
The maximum difference is 99895
Time taken by your method: 0.5533690452575684
Time taken by my method: 0.08005285263061523
My method is 6.912546237558299 times faster.
Similar to what #abarnert said (who always snipes me on these things I swear), you don't want to loop over the list twice. You can exploit the fact that you know that your larger value has to be in front of the smaller one. You also can exploit the fact that you don't care for anything except the largest number, that is, in the list [1,3,8,5,9], the maximum difference is 8 (9-1) and you don't care that 3, 8, and 5 are in there. Thus: max(a[i+1:]) - a[i] is the maximum difference for a given index.
Then you compare it with diff, and take the larger of the 2 with max, as calling default built-in python functions is somewhat faster than if curr_diff > diff: diff = curr_diff (or equivalent).
The return line is simply your (fixed) line in 1 line instead of 4
As you can see, in a sample of 1000, this method is ~6x faster (note: used python 3.4, but nothing here would break on python 2.x)
I think the expected answer for
1, 2, 4, 2, 3, 8, 5, 6, 10
will be 8 - 2 = 6 but instead Saksham Varma code will return 10 - 1 = 9.
Its max(arr) - min(arr).
Don't we have to reset the min value when there is a dip
. ie; 4 -> 2 will reset current_smallest = 2 and continue diff the calculation with value '2'.
def f2(a):
current_smallest = a[0]
large_diff = 0
for i in range(1, len(a)):
# Identify the dip
if a[i] < a[i-1]:
current_smallest = a[i]
if a[i] - current_smallest > large_diff:
large_diff = a[i] - current_smallest

Find a function that finds the difference between adjacent values in a list then test against a threshold

So basically I need a function that calculates the difference between each value in a list then tests against the threshold. If the difference between two adjacent numbers are greater than the given threshold, then the average between the two numbers should be inserted into the list sequentially. If the difference is not larger than it should return the original list. Only one number at the max should be inserted.
I have
def test(list, Threshold):
for i in range(len(list)):
if abs((list[i] - list[i+1])) > Threshold :
((list[i] + list[i+1])/2)
(list.append((list[i] + list[i+1])/2))
( list.sort())
else:
( list)
Z = [1,2,4,4.5]
test(Z,1.5)
Z = [1,2,3.0,4,4.5]
This is the only scenario that works. If none exceed the threshold or if there are two multiple that do exceed it does not work. I know I'm heading in the right direction
Simply break when you append the new number. Below is an edited version of your function. Also note I've adjusted the range of the for loop to prevent an index error. When comparing list[i] and list[i+1], i+1 can't be larger than the list size, so i must stop at len(list)-1
def test(list, Threshold):
for i in range(len(list)-1): # <-- note the change in limit
if abs(list[i] - list[i+1]) > Threshold:
list.append((list[i] + list[i+1])/2)
list.sort()
break # this will stop the loop
Tested
z = [1,2,4,4.5]
test(z,1.5)
z
[1, 2, 3, 4, 4.5]

finding the min value using loop python

I can find max value, I can find average but I just can't seem to find the min. I know there is a way to find max and min in a loop but right now I can only find the max.
def large(s)
sum=0
n=0
for number in s:
if number>n:
n=number
return n
Is there a way to find the min value using this function?
You can use Python's built-in sum(), min(), and max() functions for this kind of analysis.
However, if you're wanting to do it all in one pass or just want to learn how to write it yourself, then the process is 1) iterate over the input and 2) keep track of the cumulative sum, the minimum value seen so far, and the maximum value seen so far:
def stats(iterable):
'''Return a tuple of the minimum, average, and maximum values
>>> stats([20, 50, 30, 40])
(20, 35.0, 50)
'''
it = iter(iterable)
first = next(it) # Raises an exception if the input is empty
minimum = maximum = cumsum = first
n = 1
for x in it:
n += 1
cumsum += x
if x < minimum:
minimum = x
if x > maximum:
maximum = x
average = cumsum / float(n)
return minimum, average, maximum
if __name__ == '__main__':
import doctest
print doctest.testmod()
The code has one other nuance. It uses the first value from the input iterable as the starting value for the minimum, maximum, and cumulative sum. This is preferred over creating a positive or negative infinity value as initial values for the maximum and minimum. FWIW, Python's own builtin functions are written this way.
Finding the minimum takes the same algorithm as finding the maximum, but with the comparison reversed. < becomes > and vice versa. Initialize the minimum to the largest value possible, which is float("inf"), or to the first element of the list.
FYI, Python has a builtin min function for this purpose.
You must set n to a very high number (higher than any of the expected) or to take one from the list to start comparison:
def large(s)
n = s.pop()
for number in s:
if number < n:
n = number
return n
Obviously you have already max and min for this purpose.
A straightforward solution:
def minimum(lst):
n = float('+inf')
for num in lst:
if num < n:
n = num
return n
Explanation: first, you initialize n (the minimum number) to a very large value, in such a way that any other number will be smaller than it - for example, the infinite value. It's an initialization trick, in case the list is empty, it will return infinite, meaning with that that the list was empty and it didn't contain a minimum value.
After that, we iterate over all the values in the list, checking each one to see if it is smaller than the value we assumed to be the minimum. If a new minimum is found, we update the value of n.
At the end, we return the minimum value found.
Why not just replace large with small and > with <? Also, you might not want to initialize n to 0 if you're looking for the smallest value. Your large function only works for lists of positive numbers. Also, you're missing a ":" after your def line.
def small(s):
if len(s)==0: return None
n = s[0]
for number in s[1:]:
if n < number:
n=number
return n
This handles empty lists by returning None.
Using this function to find minimum is
min=-large(-s)
The logic is just to find maximum of the negative list , which gives the minimum value
You can use same function with iteration just instead of n=0 use n=L[0]
def min(L):
n=L[0]
for x in L:
if x
def min(s):
n=s[0]
for number in s:
if number < n:
n=number
return n

Categories

Resources