Comparing a sequence of numbers in a python list - python

I would like to make a loop to take a number, compare with the next number and if the condition is true, replace this number by the next number and compare this number to the next until this number not fits more in the condition.
I tried this code but the looping does not work.
list = [9,4,3,1,8,10,4,3,2]
for i,item in enumerate(list):
p = item
while p > list[i+1]:
p = list[i+1]
else:
print(p)

You can find the local minima (I want the output the number: 1 and 2. (the minimal point in a wave)) for your list:
>>> data = [9, 4, 3, 1, 8, 10, 4, 3, 2]
by adding infinity to both end so that the first and the last element will also be found as a minimum:
>>> padded = [float('inf')] + data + [float('inf')]
and comparing a value with the one to its left and its right:
>>> [v2 for v1, v2, v3 in zip(padded[:-2], padded[1:-1], padded[2:]) if v1 > v2 < v3]
[1, 2]

list = [9,4,3,1,8,10,4,3,2]
list.append(float('Inf'))
for i,item in enumerate(list[:-1]):
if i == 0:
# skip this one, but make i count from 0
continue
if list[i-1] > item < list[i+1]:
print(item)

Related

How can I move zeroes to the end of a list?

I have an array of integers like:
nums = [0, 1, 0, 3, 12]
I want to move all '0's to the end of it, while maintaining the relative order of the non-zero elements. So the desired output is [1, 3, 12, 0, 0].
I made the following attempts:
temp = 0
for i in range(len(nums)):
if nums[i] == 0:
nums.pop(i)
temp += 1
print(temp)
In this code, I got an error saying that nums[i] has an index out of range. Why? len(nums) == 5, so the i values should all be valid.
nums = [0,1,0,3,12]
nums.sort()
temp = 0
for i in range(len(nums)-1):
if nums[i] == 0:
print(nums[i])
temp +=1
nums.pop(i)
print(nums)
for _ in range(temp):
nums.append(0)
print(nums)
With this code, the first print gives an output of [0, 1, 3, 12], so in the final result, not all of the zeroes are moved. Why were they not all popped by the first loop?
I think one way you can get the desired output is to separate the nums list into two list that doesn't contain zeros and one does using list comprehension and concat the two list together
nums = [0,1,0,3,12]
new_list = [n for n in nums if n != 0] + [n for n in nums if n == 0]
Edit: per #DanielHao's suggestion, you can also use sorted key lambda with lambda x: not x which will then interprets zeroes as 1 and non-zeroes as 0 when sorting the list
nums = [0,1,0,3,12]
nums[:] = sorted(nums, key=lambda x: not x)
nums = [0, 1, 0, 3, 12]
temp =0
new_nums=[]
for x in range(0,len(nums)):
if(nums[x]==0):
temp +=1
else:
new_nums.append(nums[x])
while(temp != 0):
new_nums.append(0)
temp -=1
print(new_nums)
This code work efficiently to produce desired output.
Q1) When you pop out the item, the length of nums is decreased. For loops will not adjust the range being iterated over, so in this case range(len(nums)) will always be range(5) as this was the original length. This means that nums[4] is called, which results in an index error because the item that used to be at this index has moved backwards in the list due to the removal of prior values.
A solution is to use a while loop, as the condition i < len(nums) will be checked at every iteration. You will have to manually increment i.
Q2) If the indices of values in the list decreases as items are popped, some values will be skipped.
A solution in tandem with a while loop is to only increment i if the condition nums[i] == 0 is not met.
nums = [0,1,0,3,12]
nums.sort()
temp = 0
i = 0
while i < len(nums):
if nums[i] == 0:
print(nums[i])
temp += 1
nums.pop(i)
else:
i += 1
print(nums)
for _ in range(temp):
nums.append(0)
print(nums)
There are definitely easier ways to solve the same problem, as shown in other solutions, but I hope this way is easy to understand.
1] You are popping the list element so the list length changes hence getting out of index error
2] Code:
nums = [0,1,0,3,12]
# Get count of 0's
count = nums.count(0)
# List without 0's
nums = [ i for i in nums if i!=0 ]
# Add 0's to the end
[nums.append(0) for i in range(count)]
print(nums)

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

Unique sums greater than a number

So I'm trying to write a code that takes a list of numbers between 1 and 10 and finds sums that are greater or equal than 10 and then remove those numbers from the list. Here's the twist: first you need to check if there is any 10 in the list, the any couple of numbers that sum to 10, then any 3 numbers and so on until 5. Also, the lower the numbers summed the better. So you need to get rid of most numbers when summing couples. So far I managed to do the couples:
n = input("How many numbers in the list? \n")
throw = []
for i in range(int(n)):
throw.append(random.randint(1, 10))
throw.sort()
increments = 0
print(throw)
increments += throw.count(10)
throw = list(filter(lambda i: i != 10, throw))
high = len(throw)-1
low = 0
acceptable_couples = []
get_rid = []
while low < high:
sums = throw[high] + throw[low]
if sums >= 10:
increments += 1
get_rid.append(throw[high])
get_rid.append(throw[low])
acceptable_couples.append((throw[high], throw[low]))
high -= 1
low += 1
else:
low += 1
for i in get_rid:
throw.remove(i)
I also did the pairs of 3 and was thinking to apply the same method for 4, and 5:
while len(throw) >= 3:
z = 0
x = list(itertools.combinations(throw, 3))
for couple in x:
if sum(couple) >= 10:
z += 1
i = list(couple)
increments += 1
for j in couple:
throw.remove(j)
break
else:
continue
if z == 0:
break
I was hoping to find a less messy way to do it. This works, but for large number of numbers it seems a lot of useless computation.
Any ideas?
In that case perhaps this would be a solution. In pseudo code:
Read list of numbers and sort from high to low
remove all numbers 10 from the list and add these as a solution
Loop until list is empty
take the largest number in the list (which is the first number as list is sorted) and remove it from the list
Check if by adding the smallest number we can get a sum greater or equal to 10 if not go to a bigger number until we complete the loop. Break loop if a solution is found, add to solutions and remove the element from the list that solved it.
if solved break and repeat the outer while loop with next biggest number in the list. If not solved then add the next biggest number to the sum and remove it from the list and check if we can find a solution adding smaller numbers running the for loop again
Code
import random
n = int(input("How many numbers in the list? \n"))
throw = [random.randint(1, 6) for _ in range(n)]
print(throw)
throw.sort(reverse=True)
print(throw)
list_of_solved_sets = []
# remove all numbers 10 from the list and add a solution
while throw and throw[0] == 10:
list_of_solved_sets.append([throw[0]])
del throw[0]
while throw:
# take the largest number in the set (which is the first number
# as list is sorted) and remove it from the list
solved_set = [throw[0]]
_sum = throw[0]
del throw[0]
while throw:
solved = False
# Check if by adding the smallest number we can get
# a sum greater or equal to 10 if not go to a bigger number
# until we complete the loop. Break loop if a solution is found, add
# to solutions and remove element from the list that solved it
for j in range(len(throw) - 1, -1, -1):
if _sum + throw[j] >= 10:
solved_set.append(throw[j])
del throw[j]
list_of_solved_sets.append(solved_set)
solved = True
break
# if solved break and repeat the outer while loop with next biggest number
# in the list. If not solved then add the next biggest number to the sum and
# check if we can find a solution adding smaller numbers running the for
#loop again
if solved:
break
else:
_sum += throw[0]
solved_set.append(throw[0])
del throw[0]
print('List of solved sets:')
for i, solved_set in enumerate(list_of_solved_sets):
print(f' {i+1}: {solved_set}')
Result example:
How many numbers in the list?
10
[3, 2, 5, 1, 6, 3, 4, 3, 2, 1]
[6, 5, 4, 3, 3, 3, 2, 2, 1, 1]
List of solved sets:
1: [6, 4]
2: [5, 3, 2]
3: [3, 3, 2, 1, 1]
Not sure if I understand your question correctly. My interpretation is that you have a set of numbers between 1 and 10 and you need to find the longest sub sets of numbers from this set that sum up to 10 or greater and then remove these numbers from the original set until you can not find any more sets with more than one number.
If this is the correct interpretation than the following should work:
import random
n = int(input("How many numbers in the list? \n"))
throw = [random.randint(1, 10) for _ in range(n)]
print(throw)
throw.sort()
list_of_solved_sets = []
sets_found = True
while sets_found:
_sum = 0
solved_set = []
solved_indexes = []
for index, element in enumerate(throw):
_sum += element
solved_set.append(element)
solved_indexes.append(index)
if _sum >= 10:
break
if len(solved_set) <= 1:
sets_found = False
else:
list_of_solved_sets.append(solved_set)
for index in reversed(solved_indexes):
del throw[index]
print('List of solved sets:')
for i, solved_set in enumerate(list_of_solved_sets):
print(f' {i+1}: {solved_set}')
Note you need to remove the indexes from the list throw in reversed order!

Find consecutive integers in a list

I am trying to find consecutive values from an unsorted list. Experimental code below:
num = [8, 9, 4, 1, 2, 3]
#(num[0+1]) next value
for i in range(len(num)-1): # not using -1 will cause index error
if num[i]+1==num[i+1]:
print('Con',num[i])
Problem: I am unable to get the last value with this current code. My output excludes the last value. Here is what I get (no 9 or no 3):
Con 8
Con 1
Con 2
I have seen a few complex solutions which were a little difficult for me to understand. Is it possible to tweak the for loop part a little and get the entire sequence? Thanks a lot.
You can use the function groupby:
from itertools import groupby
num = [8, 9, 4, 1, 2, 3]
# Enumerate and get differences between counter—integer pairs
# Group by differences (consecutive integers have equal differences)
gb = groupby(enumerate(num), key=lambda x: x[0] - x[1])
# Repack elements from each group into list
all_groups = ([i[1] for i in g] for _, g in gb)
# Filter out one element lists
list(filter(lambda x: len(x) > 1, all_groups))
# [[8, 9], [1, 2, 3]]
This is because you only check the next number. When you want the second number (like 9 or 3), you have to include a check for the previous number too. This will make the if a bit longer, but it'll work.
num=[8,9,4,1,2,3]
for i in range(len(num)):
if (
( # check for the next number
i + 1 != len (num) and # don't check the end of the list
num[i]+1==num[i+1]
) or ( # check for the previous number
i != 0 and # don't check before the list
num [i-1] == num [i] - 1
)
): print('Con',num[i])
Also, I had to remove the -1 in your range, because I already do a manual check, and as pointed out, this prvented 3 from being shown.
Your code only tests in one direction (being followed by a consecutive number).
For the full sequence you have to test in both direction.
num=[8,9,4,1,2,3]
assert(len(num) > 1)
for i, n in enumerate(num):
if i != 0:
if n == num[i-1] + 1:
print("Con", n)
continue
if i != len(num) - 1:
if n == num[i+1] - 1:
print("Con", n)
One way would be to print both numbers when you found them to be consecutive, but also check that the one at index i-1 was not in the consecutive list as well so that the number at index i is not printed twice:
num = [8, 9, 4, 1, 2, 3]
for i in range(len(num)-1): # not using -1 will cause index error
if num[i] + 1 == num[i + 1]:
if i == 0 or (i - 1 >= 0 and num[i - 1] != num[i] - 1):
print('Con', num[i])
print('Con', num[i + 1])
Could try with a more complex list as well:
num = [8, 9, 4, 1, 2, 3, 4, 4, 8, 9, 1, 2, 3, 0, 1, 5, 6, 1]
for i in range(len(num)-1): # not using -1 will cause index error
if num[i] + 1 == num[i + 1]:
if i == 0 or (i - 1 >= 0 and num[i - 1] != num[i] - 1):
print('Con', num[i])
print('Con', num[i + 1])
num = [8, 9, 4, 1, 2, 3]
def con(rng, pos=0):
if pos < len(rng):
if (pos > 0 and rng[pos]-1 == rng[pos-1]) or (pos < len(rng) -1 and rng[pos]+1 == rng[pos+1]):
print("con", rng[pos])
con(rng, pos+1)
con(num)
edit:
this is solution is based on concurrent function, and needs only the list as argument. As long as they are within lower-/upperbound of list, the function will check if (previous number)-1 or (next number)+1 are equal (this number)
output will be:
con 8
con 9
con 1
con 2
con 3

Selection Sort (low to high) python

I am trying to write a selection sort algorithm for sorting lists of numbers from lowest to highest.
def sortlh(numList):
if type(numList) != list:
print("Input must be a list of numbers.")
else:
inf = float("inf")
sortList = [0]*len(numList)
count = 0
while count < len(numList):
index = 0
indexLowest = 0
lowest = numList[index]
while index < (len(numList) - 1):
if numList[index + 1] < numList[index]:
lowest = numList[index + 1]
indexLowest = index + 1
index = index + 1
else:
index = index + 1
sortList[count] = lowest
numList[indexLowest] = inf
count = count + 1
return sortList
When I run this code on:
sortlh([9,8,7,6,5,4,3,2,1])
I get (as expected):
[1, 2, 3, 4, 5, 6, 7, 8, 9]
However, when I try another example, I get:
sortlh([1,3,2,4,5,7,6,9,8])
[8, 6, 9, 2, 4, 5, 7, 1, 3]
Does anyone see what is going on here?
Here is how I would suggest rewriting your program.
def sortlh(lst_input):
lst = list(lst_input) # make a copy of lst_input
i = 0
while i < len(lst):
j = i + 1
i_lowest = i
lowest = lst[i_lowest]
while j < len(lst):
if lst[j] < lowest:
i_lowest = j
lowest = lst[i_lowest]
j += 1
lst[i], lst[i_lowest] = lst[i_lowest], lst[i] # swap
i += 1
return lst
test = [9,8,7,6,5,4,3,2,1]
assert sortlh(test) == sorted(test)
test = [1,3,2,4,5,7,6,9,8]
assert sortlh(test) == sorted(test)
We don't test the type of the input. Anything that acts like a list will work, and even an iterator will work.
We don't "mutate" the original input list. We only work on a copy of the data.
When we find the lowest number, we swap it with the first number, and then only look at the remaining numbers. Thus we have less work to do on each loop as we have fewer and fewer unsorted numbers.
EDIT:
If you are a beginner, this part might seem too tricky. If it confuses you or you don't like it, just ignore it for now.
This is a more-advanced way to solve this problem in Python. The inner loop simply finds the lowest number and the index of the lowest number. We can use the Python built-in function min() to do this!
We build a "generator expression" that loops over the list, yielding up tuples. Each tuple is the number and its position. Since we want lower numbers to sort lower, we put the number first in the tuple so that min() can properly compare the tuples. Then min() will find the lowest tuple and we get the value and index.
Also, the outer loop is now a for loop with enumerate rather than a while loop using indexing.
def sortlh(lst_input):
lst = list(lst_input) # make a copy of lst_input
for i, x in enumerate(lst):
lowest, i_lowest = min((n, j) for j, n in enumerate(lst) if j >= i)
lst[i], lst[i_lowest] = lst[i_lowest], lst[i] # swap
return lst
test = [9,8,7,6,5,4,3,2,1]
assert sortlh(test) == sorted(test)
test = [1,3,2,4,5,7,6,9,8]
assert sortlh(test) == sorted(test)

Categories

Resources