Second largest integer without .sorted [duplicate] - python

This question already has answers here:
Find max with negative numbers
(3 answers)
Closed 12 months ago.
def second_largest(numbers):
first = 0
second = 0
for n in numbers:
if n > first:
first, second = n, first
elif first > n > second:
second = n
return second or None
print(second_largest([2,2,2,-2]))
When i run this code, output is None, but i need it to be -2 and also i cant use functions as .sorted and others for array. I think that problem is in second = 0 ,but i dont know how to fix it.

Here's a few issues I see.
You are instantiating first and second incorrectly (what if the largest number is negative)?
The only time you'd want to return None is if your list size is smaller than 2.
Change your return condition to return second.
def second_largest(numbers):
if len(numbers) < 2:
return None
first, second = numbers[0], numbers[1]
if first < second:
first, second = second, first
for n in numbers[2:]:
if n > first:
first, second = n, first
elif n > second:
second = n
return second

Not sure if this is what you're looking for, but you can basically take the largest element out of the list (or make a note of it) and then search for the second-largest element in what's left. Here, I do this by first using max() (a built-in function of python that works on any iterable object) to get the largest element of the list, then using a list comprehension to create a second list of elements that do not equal that largest element, and finally using max() again to get the second-largest element from the original list.
def second_largest(numbers):
first = max(numbers)
second = max([i for i in numbers if i != first])
return second
You could use a for loop for this if you didn't want to use max() for some reason.

The code you provided does not handle cases where n == first. Changing elif first > n > second to elif n > second should be sufficient (you do not need to test if first >= n since if control can reach that line n > first must be false).

Not use sorted?
values = [2,2,2,-2]
values.sort(reverse=True) # technically correct
second_largest = values[1]
or, less facetious
values = set([2,2,2,-2])
values.remove(max(values))
second_largest = max(values)
Or even
import heapq
heapq.nlargest(2, [2,2,2,-2])

def second_largest(numbers):
if len(numbers) < 2:
return "less than 2 numbers"
temp1,temp2 = numbers[0], numbers[1]
if temp1 < temp2:
temp1, temp2 = temp2, temp1
for i in range(len(numbers)):
if numbers[i] > temp2:
if numbers[i] > temp1:
temp2 = temp1
temp1 = numbers[i]
else:
temp2 = numbers[i]
else:
if(temp1==temp2):
temp2 = numbers[i]
return temp2

Related

How to find the second lowest and second highest element in a list?

So, the function works with no errors, but the output for min2(2nd lowest value) in the list is incorrect. I cant seem to find the solution.
Python 3.8.6
def max2min2(list1):
max1=list1[0]
min1=list1[0]
max2=None
min2=None
for item in list1:
if item>max1:
max2=max1
max1=item
elif max2==None or max2<item:
max2=item
if item<min1:
min2=min1
min1=item
elif min2==None or min2>item:
min2=item
return max2,min2
list1 = [1,2,3]
max2,min2=max2min2(list1)
print(min2,max2) # 1 2
With the simple input list of [1,2,3] the output of maxmin2 is (1,2), although the expected output is (2,2).
Now if this does not to need to be speed optimized, simple way would be just take a set of the numbers, sort them, and take the second element from each end:
vals = [1,1,3,2,2]
filtered_vals = sorted(set(vals))
and then
# Second lowest
In [37]: filtered_vals[1]
Out[37]: 2
# Second highest
In [36]: filtered_vals[-2]
Out[36]: 2
add some Exception and special case handling if needed.
A simple and readable solution is to sort the list first, then directly index the values you want. I added a unique argument which specifies whether you want to look at the number values (most intuitive) or keep duplicate values in the list (so that the second highest number in [1,2,2] is 2).
def second_lowest_and_highest_using_sort(nums, unique=True):
if unique:
nums = list(set(nums))
if len(nums) == 1:
raise ValueError('Second lowest/highest number is undefined for a list of length 1.')
nums = sorted(nums)
return (nums[1], nums[-2])
A more verbose approach without sorting first:
def second_lowest_and_highest(nums, unique=True):
if unique:
nums = list(set(nums))
if len(nums) == 1:
raise ValueError('Second lowest/highest number is undefined for a list of length 1.')
lowest, highest = float('inf'), float('-inf')
second_lowest, second_highest = None, None
low_delta, high_delta = float('inf'), float('inf')
for num in nums:
low_delta_new = num - lowest
if low_delta_new < 0:
second_lowest = lowest
lowest = num
elif low_delta_new <= low_delta:
second_lowest = num
low_delta = low_delta_new
high_delta_new = num - highest
if high_delta_new > 0:
second_highest = highest
highest = num
elif high_delta_new <= high_delta:
second_highest = num
high_delta = high_delta_new
return (second_lowest, second_highest)

Get list of numbers form Array Whose sum is X [duplicate]

This question already has answers here:
Finding all possible combinations of numbers to reach a given sum
(32 answers)
Closed 2 years ago.
I have a number let say 27 and a list of NumbersList. How do I get some selected numbers from NumbersList whose some is 27. And also using the most greater numbers from NumbersList
It can be done by going threw all the possibilities but deep down I know there is a simple solution and I am overthinking it.
#available numbers
NumbersList = [1,5,9,4,6,8,12,12,1,3,6,8,7,8,2]
def GetNumbers(number):
global NumbersList
tmpList = []
#Some magical code
return tmpList
#now result have
result = GetNumbers(27)
# result is [12, 12, 3]
# 12+12+3 using most possible greater numbers from "NumbersList"
You can try
NumbersList = [1,5,9,4,6,8,12,12,1,3,6,8,7,8,2]
def GetNumbers(number):
result = []
for i in sorted(NumbersList, reverse=True):
if sum(result) + i <= number:
result.append(i)
return result
OR if the NumbersList is large then you can reduce iteration by
def GetNumbers(number):
result = []
for i in sorted(NumbersList, reverse=True):
sum_list = sum(result)
if sum_list + i == number:
result.append(i)
return result
elif sum_list + i < number:
result.append(i)
return result
print(GetNumbers(27))
Output
[12, 12, 3]
This is one way to do it
NumbersList = [1,5,9,4,6,8,12,12,1,3,6,8,7,8,2]
def GetNumbers(NumbersList, number):
tmpList = []
summ = 0
srtd = sorted(NumbersList)
for i in range(len(srtd)-1, 0, -1):
if summ + srtd[i] > number:
break
summ += srtd[i]
tmpList.append(srtd[i])
for i in range(len(NumbersList)):
if NumbersList[i] == number - summ:
tmpList.append(NumbersList[i])
if sum(tmpList) == number:
return tmpList
else:
return None
result = GetNumbers(NumbersList, 27)
print(result)
Certainly not the best, but does the work for this one.
First, you sort the list, find all the biggest numbers which does not exceeds the limit. Then you find the missing number.
If there is, return the array.
If there is not, we return None.
This code will not work for all cases, but a good one to start with.
Easyest way to do it, is to sort the list, loop it through backwards, then
Is there room for the next number?
If there is, you can add it to the list.
If there is not, skip.
At the end you should check the sum of yout tmpList. There is a possibility that its sum is != your intended number.

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

How to create a piece of code which checks a number for its greatest prime factor?

I was trying to make a program which would check a number for its greatest prime factor. I was almost done when this error message came up. list index out of range.
What does this mean and what is wrong with my code?
Here is my code.
def is_prime(n):
for i in range(3, n):
if n % i == 0:
return False
return True
def Problem3():
x = 144
n = 2
not_a_factor = []
z = []
prime = []
not_a_prime = []
while n < x:
if x%n == 0:
z.append(n)
else:
not_a_factor.append(n)
n = n + 1
for i in z:
if is_prime(z[i]) == True:
prime.append(z[i])
else:
not_a_prime.append(z[i])
print(prime)
Problem3()
You're just a bit off. for-loops in Python iterate an object and return it's entities, not a pointer/ index.
So just use the thing you get from each iteration of 'z'
(Side note: might want to check out this post, it'll help you make your is_prime function more performant)
def is_prime(n):
for i in range(3, n):
if n % i == 0:
return False
return True
def Problem3():
x = 144
n = 2
not_a_factor = []
z = []
prime = []
not_a_prime = []
while n < x:
if x%n == 0:
z.append(n)
else:
not_a_factor.append(n)
n =+ 1 # Python version of n++
for i in z: # Python for-loop is more like a say "for each", no need for the indexing
if is_prime(i): # no need for '=='; Python will 'truthify' your object
prime.append(i)
else:
not_a_prime.append(i)
print(prime)
Problem3()
"list index out of range - what does this mean?"
The message list index out of range refers to an IndexError. Basically, this means that you are attempting to refer to an index in a list that doesn't exist.
Using your code as an example: you generate a list, z, containing the factors of the number 144. You then iterate through each element in this list (for i in z:). This means that for the:
1st iteration: i is the 1st element in z, which is 2;
2nd iteration: i is the 2nd element in z, which is 3;
and so on.
Then, you attempt if isprime(z[i]) == True:. So, as written, your program works like this:
1st iteration: if isprime(z[2]) == True:;
2nd iteration: if isprime(z[3]) == True:;
...
8th iteration: if isprime(z[16]) == True:
At this point, your code prompts an IndexError, because there are only 13 elements in z.
"what is wrong with my code?"
One way to get the result that you want is to iterate through range(len(z)) instead of each element of z. So, adjust the line for i in z to for i in range(len(z)).
Additionally, since prime is a list, and you want to return the greatest prime factor, change print(prime) to print(max(prime)).
These two changes will give you the result you are looking for.
Additional Learnings
Overall, your program could be written much more efficiently. If you want a simple algorithm to determine the greatest prime factor of a number, here is one possibility:
def greatest_prime_factor(n):
greatest_prime = 1
for i in range(n + 1):
# iterate through range(n). We skip index 0.
if i == 0:
continue
# determine if the number i is a factor of n.
if n % i == 0:
# determine if the number i is prime.
for i_ in range(2,i):
if i % i_ == 0:
break
else:
# update greatest_prime.
greatest_prime = max(greatest_prime, i)
return greatest_prime
print (greatest_prime_factor(144))
This algorithm saves a lot of memory space when compared with your original program by not initializing lists to store numbers that are primes, that aren't primes, etc. If you want to store those values, that's up to you; there are just far more efficient possibilities for what you appear to want to achieve.
Check this link for some more info on algorithmic efficiency and how to think about time and space complexity.

Trouble with Basic Python exercise involving lists and indexes

working on CheckIO exercises but stuck here. I need to design a function that'll find the sum of the elements with even indexes (0th, 2nd, 4th...) then multiply this summed number and the final element of the array together. The input is an array, the output is a number. Oh, and for an empty array, the result has to be zero.
def checkio(array):
sum = 0
if len(array) == 0:
return 0
else:
for i in array:
if array.index(i) % 2 == 0:
sum = sum + i
final = sum*(array[len(array)-1])
return final
for instance, with the array [-37,-36,-19,-99,29,20,3,-7,-64,84,36,62,26,-76,55,-24,84,49,-65,41], this function is returning -1476 when it should be giving out 1968.
As far as I can see the issue is that you are assuming all numbers in the array are unique. For example lets say I have the following array:
[0,33,33,22,22]
obviously in this array you need the 3nd and 5th elements (index 2 and 4).
with your current code however this will never happen and you will end up with a sum of 0. This is because the code:
array.index(i)
finds the first element that matches i, this would be the 2nd and 4th elements (index 1 and 3), which are odd indexes, and thus will not be added.
You can use List Comprehension. Like:
sum([i for i in L[::2]])*L[-1]
In your code array.index(i) is problem . So you can use for finding elements by using array[::2]
You can try with your code:
def checkio(array):
sum = 0
if len(array) == 0:
return 0
else:
for i in array[::2]:
sum = sum + i
final = sum*array[-1]
return final
Example:
L = [-37,-36,-19,-99,29,20,3,-7,-64,84,36,62,26,-76,55,-24,84,49,-65,41]
Output:
1968
Here is a working program I made.
def checkio(array):
listSum = 0
if array:
for i in range(0, len(array), 2):
listSum += array[i]
finalValue = listSum * array[-1]
return finalValue
else:
return 0
First, it checks to see if the array has any values. We can do that like this: if array:. If the array is empty, it will return 0 like you wanted.
Now, this is what checks every other element in your array: range(0, len(array), 2): This means that the value of i will start at 0, continue for the length of the array, and count by twos.
The sums are added here: listSum += array[i]. This takes the variable listSum and adds the value of the number at the index i in the array to it. the += operator is shorthand for listSum = listSum + array[i].
The last part of the function, takes the listSum variable, and multiplies it by array[-1] which gets the last value in the array and finnaly returns it.
When I ran your example array above, it returned 1968 as it should.
I think it is in order to to some beginner's explanation even if I'm repeating what other answers already said:
As for why your code does not work, let's change the original a little:
def checkio(array):
sum = 0
if len(array) == 0:
return 0
else:
for i in array:
print "pos of %s = %i" % (i, array.index(i))
if array.index(i) % 2 == 0:
sum = sum + i
final = sum*(array[len(array)-1])
return final
This yields
pos of -37 = 0
pos of -36 = 1
pos of -19 = 2
pos of -99 = 3
[...]
pos of 84 = 9
[...]
pos of 84 = 9
There's your problem, because index() yields the index of the first occurrence of an element and 84 appears twice. Your code only works when the elements in the array are unique, which they are not.
So, when not going for the all out python swagger using slicing:
def checkio(array):
# sum is a built-in, don't override it
result = 0
# "if len(array) != 0" is the same as "if array"
if array:
# enumerate is nice, but not really needed, see below
for i, x in enumerate(array):
# i is the index, x is the value
if i % 2 == 0:
# += is also nice
result += x
result *= array[-1]
return result
As for a more pythonic solution, you can do a lot with slicing.
array[::2]
is every second element of array and
array[-1]
is the last element. Hence
s = sum(array[::2]) * array[-1]
That does not handle an empty array, thus
# if there are no elements or only the last element, the sum is zero
if len(array) == 0:
return 0
else:
return sum(array[::2]) * array[-1]
or even
return sum(array[::2]) * array[-1] if array else 0
Which is python's equivalent of the ternary operator.
Just use enumerate to interate for each element with an index and keep track of the last element.
def checkio(array):
sum = 0
last_element = 0
for index, element in enumerate(array):
if index % 2 == 0:
sum += element
last_element = element
return last_element * sum

Categories

Resources