Finding the "centered average" of a list - python

"Return the "centered" average of a list of integers, which we'll say is the mean average of the values, except ignoring the largest and smallest values in the list. If there are multiple copies of the smallest value, ignore just one copy, and likewise for the largest value. Use integer division to produce the final average. You may assume that the list is length 3 or more."
This is a problem I have from my homework assignment and I am stumped at how to find the the largest/smallest numbers and cut them out of the list. Here is what I have so far. and It works for 10/14 the scenarios that I have to pass.. I think it is just because it grabs the median
def centered_average(nums):
x = 0
for i in range(len(nums)):
x = i + 0
y = x + 1
if y%2 == 0:
return (nums[y/2] + nums[(y/2)+1]) / 2
else:
return nums[y/2]

Sorting the array is certainly terser code, here's an alternative with a manual loop
max_value = nums[0]
min_value = nums[0]
sum = 0
for x in nums:
max_value = max(max_value, x)
min_value = min(min_value, x)
sum += x
return (sum - max_value - min_value) / (len(nums) - 2)
This just adds everything in and removes the max and min at the end.

If the list isn't too long, it shouldn't be too computationally expensive to sort the list:
sorted(nums)
Then you can create a new list without the first and last entries, which will be the smallest and largest values:
new_nums = sorted(nums)[1:-1] # from index 1 to the next-to-last entry

Before i start i know there are easier ways mentioned in the other answers using the function sort, yes that is true but i believe your teacher must have iven you this to able to master loops and use them logically.
First pick your first number and assign it to high and low, don't worry it will make sense afterwards.
def centered average(nums):
high = nums[0]
small = nums[0]
Here is were the magic happens, you loop through your list and if the number your on in the loop is larger then the previous ones then you can replace the variable high with it, let me demonstrate.
for count in nums:
if count > high:
high = count
if count < low:
low = count
Now you have the low and the high all you do is add the values of the loop together minus the high and the low (as you said you do not need them).Then divide that answer by len of nums.
for count in nums:
sum = count + sum
sum = sum - (high + low)
return sum

New here. I like to check my solutions with solutions found on the internet and did not see my code here yet (hence the post). I found this challenge on https://codingbat.com/prob/p126968. And here is my solution:
** This is done in Python 3.9.1.
First the min and max are popped from the list with the index method. After it's just a simple avg calculation.
def centered_average(nums):
nums.pop(nums.index(max(nums)))
nums.pop(nums.index(min(nums)))
return sum(nums)/len(nums)

If I understand the question, this should work:
def centered_average(nums):
trim = sorted(nums)[1:-1]
return sum(trim) / len(trim)

def centered_average(nums):
nums = sorted(nums)
for i in range(len(nums)):
if len(nums)%2 != 0:
return nums[len(nums)/2]
else:
return ((nums[len(nums)/2] + nums[len(nums)/2 - 1]) / 2)

This is a very sub standard solution to the problem. This code is a bad code that does not take into account any consideration for complexity and space. But I think the thought process to be followed is similar to the steps in the code. This then can be refined.
def centered_average(nums):
#Find max and min value from the original list
max_value = max(nums)
min_value = min(nums)
#counters for counting the number of duplicates of max and min values.
mx = 0
mn = 0
sum = 0
#New list to hold items on which we can calculate the avg
new_nums = []
#Find duplicates of max and min values
for num in nums:
if num == max_value:
mx += 1
if num == min_value:
mn += 1
#Append max and min values only once in the new list
if mx > 1:
new_nums.append(max_value)
if mn > 1:
new_nums.append(min_value)
#Append all other numbers in the original to new list
for num in nums:
if num != max_value and num != min_value:
new_nums.append(num)
#Calculate the sum of all items in the list
for new in new_nums:
sum += new
#Calculate the average value.
avg = sum/len(new_nums)
return avg

def centered_average(nums):
min1=nums[0]
max1=nums[0]
for item in nums:
if item > max1:
max1 = item
if item < min1:
min1 = item
sum1=(sum(nums)-(min1+max1))/(len(nums)-2)
return sum1

simple solution
def centered_average(nums):
b=nums
ma=max(b)
mi=min(b)
l=(len(b)-2)
s=sum(b)-(ma+mi)
av=int(s/l)
return av

use sum function to sum the array
max and min functions to get the biggest and smallest number
def centered_average(nums):
return (sum(nums) - max(nums) - min(nums)) / (len(nums) - 2)

def centered_average(nums):
sorted_list = sorted(nums)
return sum(sorted_list[1:-1])/(len(nums)-2)
This will get the job done.

Python 3 Solution using list.index, list.pop, min and max functions.
def solution(input):
average = 0
minimum = min(input)
maximum = max(input)
input.pop(input.index(minimum))
input.pop(input.index(maximum))
average = round(sum(input) / len(input))
return average

def centered_average(nums):
nums.remove((min(nums)))
nums.remove((max(nums)))
new_nums=nums
count = 0
for i in range(len(new_nums)):
count+=1
ans=sum(new_nums)//count
return ans

def centered_average(nums):
maximums = []
minimums = []
sum_of_numbers = 0
length =len(nums) + (len(minimums)-1) + (len(maximums)-1)
for i in nums:
if i == max(nums):
maximums.append(i)
elif i == min(nums):
minimums.append(i)
else:
sum_of_numbers += i
if len(maximums)>=2 or len(minimums)>=2:
sum_of_numbers = sum_of_numbers + (max(nums)*(len(maximums)-1))(min(nums)*(len(minimums)-1))
return sum_of_numbers / length

Related

Subset sum with minimum elements

Given a sorted list of integers, always containing 1. Find a target value using the minimum amount of elements to sum to the target value. All numbers can be used more than one.
e.x. {1,9,10} Target = 18, solution is 2 elements (9 twice).
{1,3,5,7} Target = 15, solution is 3 elements (7,7,1 or 5,5,5)
I understand that we should check whether we use an element up to its maximum amount to fill the target value but I am confused on how to correctly count the number of elements used once we have a correct recursive return.
def main():
sections = list(map(int,input().split(" ")))
t = int(input())
print((subset_sum(sections,len(sections)-1,t)), "elements minimum")
def subset_sum(X, i, t):
count = 0
if t == 0:
return 1
if t < 0 or abs(i) == len(X):
return 0
for z in range(0,t//X[i]):
count += subset_sum(X,i-1,t-(z*X[i]))
return count
if __name__ == "__main__":
main()
Is my base case incorrect? Since I want the minimum should the incorrect case return 1? Or do I have a mistake when I call the recursion?
I think the code is trying to solve a different problem than the one described in the title. You seem to be counting the number of different ways to make change for amount t using denominations in X. Here is a version of your code that does this:
def subset_sum(X, i, t):
count = 0
if t == 0:
return 1
if t < 0 or i < 0:
return 0
for z in range(0,t//X[i] + 1):
count += subset_sum(X,i-1,t-(z*X[i]))
return count
subset_sum([5, 2, 1], 2, 30) # 58 ways to make change
# same as the following Mathematica code:
# Length#IntegerPartitions[30, All, {1, 2, 5}]
In order to find the minimum number of coins needed to achieve amount t, you need to modify your inductive step. Instead of adding the amounts for smaller values of t, you need to take the minimum:
from functools import lru_cache
def coin_change(denominations, target):
'Return minimum number of coins with given denominations to make a target sum'
#lru_cache(None)
def f(target):
if target == 0:
return 0
elif target < 0:
return float("inf")
return min(f(target - d) for d in denominations) + 1
return f(target)
coin_change([1, 2, 5], 30) # minimum number of coins is 6

Eliminating nearest elements from a list or range

So what I have to do is find the smallest number among those that are in the list, and remove from the list both that number and whichever of its current immediate neighbors is larger. This function should repeat until the largest number in the original list gets eliminated and I have to return the number of times it took to achieve this goal. For example, [1,6,4,2,5,3] would remove element 1 and its current largest neighbor element which is 6, thus reaching the goal in 1 step. My code worked for a list but it did not work when I inputted a range in items. So could anybody help?
def elements(items):
max_value = max(items)
count = 0
while max_value in items:
n = len(items)
right_of_items = 0
left_of_items = 0
min_value = min(items)
min_value_index = items.index(min_value)
if (min_value_index -1 >= 0):
left_of_items = items[min_value_index-1]
if (min_value_index+1 < n):
right_of_items = items[min_value_index+1]
if left_of_items > right_of_items:
items.remove(left_of_items)
items.remove(min_value)
count += 1
else:
items.remove(right_of_items)
items.remove(min_value)
count += 1
return count
The problem with range is that it doesn't support access to a specific item.
So that, you either need to build a list from that range, or use more advanced algorithm which will be able to find the solution in a single pass.
As we won't know the smallest and largest items unless we're analysed the whole list, I guess, there's no such algorithm, that could solve in less than 2 passes, so consider just doing
items = list(items)
at the beginning of your function.
Also I would suggest to not to store the values of a smallest and largest items themselves. Better store their positions. So that you'll be able to access (and remove) neighbours much more effeciently. Like:
def find_largest_neighbour(lst, pos):
if pos <= 0:
return pos + 1
if pos + 1 >= len(lst):
return pos - 1
if lst[pos - 1] <= lst[pos + 1]:
return pos - 1
else:
return pos + 1
def find_min_and_max(lst):
min_pos = max_pos = 0
for i, v in enumerate(lst):
if v < lst[min_pos]:
min_pos = i
if v > lst[max_pos]:
max_pos = i
return min_pos, max_pos
def solve(lst):
number_of_iterations = 0
while True:
number_of_iterations += 1
min_pos, max_pos = find_min_and_max(lst)
max_pos_about = find_largest_neighbour(lst, min_pos)
if max_pos_about == max_pos:
# The largest item found about the smallest, we're done
break
else:
# Getting rid of the smallest item and its largest bro
del lst[min_pos]
del lst[max_pos_about]
# as we used index lookups above, we
# won't search through the list twice
return number_of_iterations

How can I count how many numbers can be fitted within particular number?

Example 1:
save([4,4,4,3,3], 12) -> 3
# 4+4+4 <= 12, but 4+4+4+3 > 12
Example 2:
save([4,4,4,3,3], 11) -> 2
# 4+4 <= 11, but 4+4+4 > 11
First of all I'm noob yet, but here is my "code" lol.
def save(sizes, hd):
sum = 0
for i in sizes:
sum = sum + i
if sum <= hd:
a = (str(sum))
print(a)
save([4,4,4,3,3], 12)
Output of this code is:
4
8
12
It would be correct if I could count length of those numbers, but I tried many ways and still couldnt found(
Thanks for helping!
You need the enumerate() function:
def save(sizes, hd):
summm = 0
for index,value in enumerate(sizes,1): # start counting at 1
summm += value
if summm <= hd:
print(summm, index) # or simply print index alone
save([4,4,4,3,3], 12)
Outputs:
12 3 # first number is the sum, second amount of numbers you added (aka 1-based index)
You can use for i in range(len(sizes)) . I think it's the fastest solution, but I'm sure it doesn't matter.
def save(sizes, hd):
sum = 0
for i in range(len(sizes)): # i values are 0,1,2,...,len(sizes)-1
sum += sizes[i] # add i-th sizes element to sum
if sum <= hd: # check if we can print answer
print(i + 1) # because i starts from 0
else: # if we can't print, we should exit cycle
break # we can use return instead
By the way, you don't need to do anything like this, because 'print()' function converts all arguments to str()
a = str(sum)
print(a)
I hope, you has learned something new!
Try this one:
def save(sizes, hd):
sum = 0
new_list = []
for i in sizes:
sum += i
new_list.append(i)
if sum >= hd:
print(new_list)
return len(new_list)
print(save([4,4,4,3,3], 12))
#print(new_list) => [4, 4, 4]
#return len(new_list) => 3
If you build a list with the cumulative sum of your sorted numbers, the position of the target value will correspond to the maximum count of numbers that will fit within your target:
from bisect import bisect_right
from itertools import accumulate
numbers = [4,4,4,3,3]
target = 12
maxCount = bisect_right(list(accumulate(sorted(numbers))),target)
print(maxCount) # 3
The bisect module provides efficient search for an index in a sorted list (bisect_right). The itertools module provides a function (accumulate) to obtain the cumulative sum of numbers in a list
I changed your code around a bit to keep it simple:
def save(sizes, hd):
size_list = [] #instead of an int, let's use a list object to hold values
for size in sizes:
size_list.append(i) # add the size to the list
if sum(size_list) <= hd: # check if sum of all values in list is <= hd
return len(size_list) # return the number of sizes inside of list
hope this helps!

Python code for printing out the second largest number number given a list [duplicate]

I'm learning Python and the simple ways to handle lists is presented as an advantage. Sometimes it is, but look at this:
>>> numbers = [20,67,3,2.6,7,74,2.8,90.8,52.8,4,3,2,5,7]
>>> numbers.remove(max(numbers))
>>> max(numbers)
74
A very easy, quick way of obtaining the second largest number from a list. Except that the easy list processing helps write a program that runs through the list twice over, to find the largest and then the 2nd largest. It's also destructive - I need two copies of the data if I wanted to keep the original. We need:
>>> numbers = [20,67,3,2.6,7,74,2.8,90.8,52.8,4,3,2,5,7]
>>> if numbers[0]>numbers[1]):
... m, m2 = numbers[0], numbers[1]
... else:
... m, m2 = numbers[1], numbers[0]
...
>>> for x in numbers[2:]:
... if x>m2:
... if x>m:
... m2, m = m, x
... else:
... m2 = x
...
>>> m2
74
Which runs through the list just once, but isn't terse and clear like the previous solution.
So: is there a way, in cases like this, to have both? The clarity of the first version, but the single run through of the second?
You could use the heapq module:
>>> el = [20,67,3,2.6,7,74,2.8,90.8,52.8,4,3,2,5,7]
>>> import heapq
>>> heapq.nlargest(2, el)
[90.8, 74]
And go from there...
Since #OscarLopez and I have different opinions on what the second largest means, I'll post the code according to my interpretation and in line with the first algorithm provided by the questioner.
def second_largest(numbers):
count = 0
m1 = m2 = float('-inf')
for x in numbers:
count += 1
if x > m2:
if x >= m1:
m1, m2 = x, m1
else:
m2 = x
return m2 if count >= 2 else None
(Note: Negative infinity is used here instead of None since None has different sorting behavior in Python 2 and 3 – see Python - Find second smallest number; a check for the number of elements in numbers makes sure that negative infinity won't be returned when the actual answer is undefined.)
If the maximum occurs multiple times, it may be the second largest as well. Another thing about this approach is that it works correctly if there are less than two elements; then there is no second largest.
Running the same tests:
second_largest([20,67,3,2.6,7,74,2.8,90.8,52.8,4,3,2,5,7])
=> 74
second_largest([1,1,1,1,1,2])
=> 1
second_largest([2,2,2,2,2,1])
=> 2
second_largest([10,7,10])
=> 10
second_largest([1,1,1,1,1,1])
=> 1
second_largest([1])
=> None
second_largest([])
=> None
Update
I restructured the conditionals to drastically improve performance; almost by a 100% in my testing on random numbers. The reason for this is that in the original version, the elif was always evaluated in the likely event that the next number is not the largest in the list. In other words, for practically every number in the list, two comparisons were made, whereas one comparison mostly suffices – if the number is not larger than the second largest, it's not larger than the largest either.
You could always use sorted
>>> sorted(numbers)[-2]
74
Try the solution below, it's O(n) and it will store and return the second greatest number in the second variable. UPDATE: I've adjusted the code to work with Python 3, because now arithmetic comparisons against None are invalid.
Notice that if all elements in numbers are equal, or if numbers is empty or if it contains a single element, the variable second will end up with a value of None - this is correct, as in those cases there isn't a "second greatest" element.
Beware: this finds the "second maximum" value, if there's more than one value that is "first maximum", they will all be treated as the same maximum - in my definition, in a list such as this: [10, 7, 10] the correct answer is 7.
def second_largest(numbers):
minimum = float('-inf')
first, second = minimum, minimum
for n in numbers:
if n > first:
first, second = n, first
elif first > n > second:
second = n
return second if second != minimum else None
Here are some tests:
second_largest([20, 67, 3, 2.6, 7, 74, 2.8, 90.8, 52.8, 4, 3, 2, 5, 7])
=> 74
second_largest([1, 1, 1, 1, 1, 2])
=> 1
second_largest([2, 2, 2, 2, 2, 1])
=> 1
second_largest([10, 7, 10])
=> 7
second_largest( [1, 3, 10, 16])
=> 10
second_largest([1, 1, 1, 1, 1, 1])
=> None
second_largest([1])
=> None
second_largest([])
=> None
Why to complicate the scenario? Its very simple and straight forward
Convert list to set - removes duplicates
Convert set to list again - which gives list in ascending order
Here is a code
mlist = [2, 3, 6, 6, 5]
mlist = list(set(mlist))
print mlist[-2]
You can find the 2nd largest by any of the following ways:
Option 1:
numbers = set(numbers)
numbers.remove(max(numbers))
max(numbers)
Option 2:
sorted(set(numbers))[-2]
The quickselect algorithm, O(n) cousin to quicksort, will do what you want. Quickselect has average performance O(n). Worst case performance is O(n^2) just like quicksort but that's rare, and modifications to quickselect reduce the worst case performance to O(n).
The idea of quickselect is to use the same pivot, lower, higher idea of quicksort, but to then ignore the lower part and to further order just the higher part.
This is one of the Simple Way
def find_second_largest(arr):
first, second = 0, 0
for number in arr:
if number > first:
second = first
first = number
elif number > second and number < first:
second = number
return second
If you do not mind using numpy (import numpy as np):
np.partition(numbers, -2)[-2]
gives you the 2nd largest element of the list with a guaranteed worst-case O(n) running time.
The partition(a, kth) methods returns an array where the kth element is the same it would be in a sorted array, all elements before are smaller, and all behind are larger.
there are some good answers here for type([]), in case someone needed the same thing on a type({}) here it is,
def secondLargest(D):
def second_largest(L):
if(len(L)<2):
raise Exception("Second_Of_One")
KFL=None #KeyForLargest
KFS=None #KeyForSecondLargest
n = 0
for k in L:
if(KFL == None or k>=L[KFL]):
KFS = KFL
KFL = n
elif(KFS == None or k>=L[KFS]):
KFS = n
n+=1
return (KFS)
KFL=None #KeyForLargest
KFS=None #KeyForSecondLargest
if(len(D)<2):
raise Exception("Second_Of_One")
if(type(D)!=type({})):
if(type(D)==type([])):
return(second_largest(D))
else:
raise Exception("TypeError")
else:
for k in D:
if(KFL == None or D[k]>=D[KFL]):
KFS = KFL
KFL = k
elif(KFS == None or D[k] >= D[KFS]):
KFS = k
return(KFS)
a = {'one':1 , 'two': 2 , 'thirty':30}
b = [30,1,2]
print(a[secondLargest(a)])
print(b[secondLargest(b)])
Just for fun I tried to make it user friendly xD
>>> l = [19, 1, 2, 3, 4, 20, 20]
>>> sorted(set(l))[-2]
19
O(n): Time Complexity of a loop is considered as O(n) if the loop variables is incremented / decremented by a constant amount. For example following functions have O(n) time complexity.
// Here c is a positive integer constant
for (int i = 1; i <= n; i += c) {
// some O(1) expressions
}
To find the second largest number i used the below method to find the largest number first and then search the list if thats in there or not
x = [1,2,3]
A = list(map(int, x))
y = max(A)
k1 = list()
for values in range(len(A)):
if y !=A[values]:
k.append(A[values])
z = max(k1)
print z
Objective: To find the second largest number from input.
Input : 5
2 3 6 6 5
Output: 5
*n = int(raw_input())
arr = map(int, raw_input().split())
print sorted(list(set(arr)))[-2]*
def SecondLargest(x):
largest = max(x[0],x[1])
largest2 = min(x[0],x[1])
for item in x:
if item > largest:
largest2 = largest
largest = item
elif largest2 < item and item < largest:
largest2 = item
return largest2
SecondLargest([20,67,3,2.6,7,74,2.8,90.8,52.8,4,3,2,5,7])
list_nums = [1, 2, 6, 6, 5]
minimum = float('-inf')
max, min = minimum, minimum
for num in list_nums:
if num > max:
max, min = num, max
elif max > num > min:
min = num
print(min if min != minimum else None)
Output
5
Initialize with -inf. This code generalizes for all cases to find the second largest element.
max1= float("-inf")
max2=max1
for item in arr:
if max1<item:
max2,max1=max1,item
elif item>max2 and item!=max1:
max2=item
print(max2)
Using reduce from functools should be a linear-time functional-style alternative:
from functools import reduce
def update_largest_two(largest_two, x):
m1, m2 = largest_two
return (m1, m2) if m2 >= x else (m1, x) if m1 >= x else (x, m1)
def second_largest(numbers):
if len(numbers) < 2:
return None
largest_two = sorted(numbers[:2], reverse=True)
rest = numbers[2:]
m1, m2 = reduce(update_largest_two, rest, largest_two)
return m2
... or in a very concise style:
from functools import reduce
def second_largest(n):
update_largest_two = lambda a, x: a if a[1] >= x else (a[0], x) if a[0] >= x else (x, a[0])
return None if len(n) < 2 else (reduce(update_largest_two, n[2:], sorted(n[:2], reverse=True)))[1]
This can be done in [N + log(N) - 2] time, which is slightly better than the loose upper bound of 2N (which can be thought of O(N) too).
The trick is to use binary recursive calls and "tennis tournament" algorithm. The winner (the largest number) will emerge after all the 'matches' (takes N-1 time), but if we record the 'players' of all the matches, and among them, group all the players that the winner has beaten, the second largest number will be the largest number in this group, i.e. the 'losers' group.
The size of this 'losers' group is log(N), and again, we can revoke the binary recursive calls to find the largest among the losers, which will take [log(N) - 1] time. Actually, we can just linearly scan the losers group to get the answer too, the time budget is the same.
Below is a sample python code:
def largest(L):
global paris
if len(L) == 1:
return L[0]
else:
left = largest(L[:len(L)//2])
right = largest(L[len(L)//2:])
pairs.append((left, right))
return max(left, right)
def second_largest(L):
global pairs
biggest = largest(L)
second_L = [min(item) for item in pairs if biggest in item]
return biggest, largest(second_L)
if __name__ == "__main__":
pairs = []
# test array
L = [2,-2,10,5,4,3,1,2,90,-98,53,45,23,56,432]
if len(L) == 0:
first, second = None, None
elif len(L) == 1:
first, second = L[0], None
else:
first, second = second_largest(L)
print('The largest number is: ' + str(first))
print('The 2nd largest number is: ' + str(second))
You can also try this:
>>> list=[20, 20, 19, 4, 3, 2, 1,100,200,100]
>>> sorted(set(list), key=int, reverse=True)[1]
100
A simple way :
n=int(input())
arr = set(map(int, input().split()))
arr.remove(max(arr))
print (max(arr))
use defalut sort() method to get second largest number in the list.
sort is in built method you do not need to import module for this.
lis = [11,52,63,85,14]
lis.sort()
print(lis[len(lis)-2])
Just to make the accepted answer more general, the following is the extension to get the kth largest value:
def kth_largest(numbers, k):
largest_ladder = [float('-inf')] * k
count = 0
for x in numbers:
count += 1
ladder_pos = 1
for v in largest_ladder:
if x > v:
ladder_pos += 1
else:
break
if ladder_pos > 1:
largest_ladder = largest_ladder[1:ladder_pos] + [x] + largest_ladder[ladder_pos:]
return largest_ladder[0] if count >= k else None
def secondlarget(passinput):
passinputMax = max(passinput) #find the maximum element from the array
newpassinput = [i for i in passinput if i != passinputMax] #Find the second largest element in the array
#print (newpassinput)
if len(newpassinput) > 0:
return max(newpassinput) #return the second largest
return 0
if __name__ == '__main__':
n = int(input().strip()) # lets say 5
passinput = list(map(int, input().rstrip().split())) # 1 2 2 3 3
result = secondlarget(passinput) #2
print (result) #2
if __name__ == '__main__':
n = int(input())
arr = list(map(float, input().split()))
high = max(arr)
secondhigh = min(arr)
for x in arr:
if x < high and x > secondhigh:
secondhigh = x
print(secondhigh)
The above code is when we are setting the elements value in the list
as per user requirements. And below code is as per the question asked
#list
numbers = [20, 67, 3 ,2.6, 7, 74, 2.8, 90.8, 52.8, 4, 3, 2, 5, 7]
#find the highest element in the list
high = max(numbers)
#find the lowest element in the list
secondhigh = min(numbers)
for x in numbers:
'''
find the second highest element in the list,
it works even when there are duplicates highest element in the list.
It runs through the entire list finding the next lowest element
which is less then highest element but greater than lowest element in
the list set initially. And assign that value to secondhigh variable, so
now this variable will have next lowest element in the list. And by end
of loop it will have the second highest element in the list
'''
if (x<high and x>secondhigh):
secondhigh=x
print(secondhigh)
Max out the value by comparing each one to the max_item. In the first if, every time the value of max_item changes it gives its previous value to second_max. To tightly couple the two second if ensures the boundary
def secondmax(self, list):
max_item = list[0]
second_max = list[1]
for item in list:
if item > max_item:
second_max = max_item
max_item = item
if max_item < second_max:
max_item = second_max
return second_max
you have to compare in between new values, that's the trick, think always in the previous (the 2nd largest) should be between the max and the previous max before, that's the one!!!!
def secondLargest(lista):
max_number = 0
prev_number = 0
for i in range(0, len(lista)):
if lista[i] > max_number:
prev_number = max_number
max_number = lista[i]
elif lista[i] > prev_number and lista[i] < max_number:
prev_number = lista[i]
return prev_number
Most of previous answers are correct but here is another way !
Our strategy is to create a loop with two variables first_highest and second_highest. We loop through the numbers and if our current_value is greater than the first_highest then we set second_highest to be the same as first_highest and then the second_highest to be the current number. If our current number is greater than second_highest then we set second_highest to the same as current number
#!/usr/bin/env python3
import sys
def find_second_highest(numbers):
min_integer = -sys.maxsize -1
first_highest= second_highest = min_integer
for current_number in numbers:
if current_number == first_highest and min_integer != second_highest:
first_highest=current_number
elif current_number > first_highest:
second_highest = first_highest
first_highest = current_number
elif current_number > second_highest:
second_highest = current_number
return second_highest
print(find_second_highest([80,90,100]))
print(find_second_highest([80,80]))
print(find_second_highest([2,3,6,6,5]))
Best solution that my friend Dhanush Kumar came up with:
def second_max(loop):
glo_max = loop[0]
sec_max = float("-inf")
for i in loop:
if i > glo_max:
sec_max = glo_max
glo_max=i
elif sec_max < i < glo_max:
sec_max = i
return sec_max
#print(second_max([-1,-3,-4,-5,-7]))
assert second_max([-1,-3,-4,-5,-7])==-3
assert second_max([5,3,5,1,2]) == 3
assert second_max([1,2,3,4,5,7]) ==5
assert second_max([-3,1,2,5,-2,3,4]) == 4
assert second_max([-3,-2,5,-1,0]) == 0
assert second_max([0,0,0,1,0]) == 0
Below code will find the max and the second max numbers without the use of max function. I assume that the input will be numeric and the numbers are separated by single space.
myList = input().split()
myList = list(map(eval,myList))
m1 = myList[0]
m2 = myList[0]
for x in myList:
if x > m1:
m2 = m1
m1 = x
elif x > m2:
m2 = x
print ('Max Number: ',m1)
print ('2nd Max Number: ',m2)
Here I tried to come up with an answer.
2nd(Second) maximum element in a list using single loop and without using any inbuilt function.
def secondLargest(lst):
mx = 0
num = 0
sec = 0
for i in lst:
if i > mx:
sec = mx
mx = i
else:
if i > num and num >= sec:
sec = i
num = i
return sec

Calculate the number of combinations of unique positive integers with minimum and maximum differences between each other?

How do I write a Python program to calculate the number of combinations of unique sorted positive integers over a range of integers that can be selected where the minimum difference between each of the numbers in the set is one number and the maximum difference is another number?
For instance, if I want to calculate the number of ways I can select 6 numbers from the positive integers from 1-50 such that the minimum difference between each number is 4 and the maximum difference between each number is 7, I would want to count the combination {1,6,12,18,24,28} since the minimum difference is 4 and the maximum difference is 6, but I would not want to count combinations like {7,19,21,29,41,49} since the minimum difference is 2 and the maximum difference is 12.
I have the following code so far, but the problem is that it has to loop through every combination, which takes an extremely long time in many cases.
import itertools
def min_max_differences(integer_list):
i = 1
diff_min = max(integer_list)
diff_max = 1
while i < len(integer_list):
diff = (integer_list[i]-integer_list[i-1])
if diff < diff_min:
diff_min = diff
if diff > diff_max:
diff_max = diff
i += 1
return (diff_min,diff_max)
def total_combinations(lower_bound,upper_bound,min_difference,max_difference,elements_selected):
numbers_range = list(range(lower_bound,upper_bound+1,1))
all_combos = itertools.combinations(numbers_range,elements_selected)
min_max_diff_combos = 0
for c in all_combos:
if min_max_differences(c)[0] >= min_difference and min_max_differences(c)[1] <= max_difference:
min_max_diff_combos += 1
return min_max_diff_combos
I do not have a background in combinatorics, but I am guessing there is a much more algorithmically efficient way to do this using some combinatorial methods.
You can use a recursive function with caching to get your answer.
This method will work even if you have a large array because some positions are repeated many times with the same parameters.
Here is a code for you (forgive me if I made any mistakes in python cause I don't normally use it).
If there is any flow in the logic, please let me know
# function to get the number of ways to select {target} numbers from the
# array {numbers} with minimum difference {min} and maximum difference {max}
# starting from position {p}, with the help of caching
dict = {}
def Combinations(numbers, target, min, max, p):
if target == 1: return 1
# get a unique key for this position
key = target * 1000000000000 + min * 100000000 + max * 10000 + p
if dict.has_key(key): return dict[key]
ans = 0
# current start value
pivot = numbers[p]
p += 1;
# increase the position until you reach the minimum
while p < len(numbers) and numbers[p] - pivot < min:
p += 1
# get all the values in the range of min <--> max
while p < len(numbers) and numbers[p] - pivot <= max:
ans += Combinations(numbers, target - 1, min, max, p)
p += 1
# store the ans for further inquiry
dict[key] = ans
return ans
# any range of numbers (must be SORTED as you asked)
numbers = []
for i in range(0,50): numbers.append(i+1)
# number of numbers to select
count = 6
# minimum difference
min = 4
# maximum difference
max = 7
ans = 0
for i in range(0,len(numbers)):
ans += Combinations(numbers, count, min, max, i)
print ans
Here is a very simple (and non-optimized) recursive approach:
Code
import numpy as np
from time import time
""" PARAMETERS """
SET = range(50) # Set of elements to choose from
N = 6 # N elements to choose
MIN_GAP = 4 # Gaps
MAX_GAP = 7 # ""
def count(N, CHOSEN=[]):
""" assumption: N > 0 at start """
if N == 0:
return 1
else:
return sum([count(N-1, CHOSEN + [val])
for val in SET if (val not in CHOSEN)
and ((not CHOSEN) or ((val - CHOSEN[-1]) >= MIN_GAP))
and ((not CHOSEN) or ((val - CHOSEN[-1]) <= MAX_GAP))])
start_time = time()
count_ = count(N)
print('used time in secs: ', time() - start_time)
print('# solutions: ', count_)
Output
('used time in secs: ', 0.1174919605255127)
('# solutions: ', 23040)
Remarks
It outputs the same solution as Ayman's approach
Ayman's approach is much more powerful (in terms of asymptotical speed)

Categories

Resources