Python while loop basics, check order of the list - python

I want to check if element in list is smaller than the next one and break function in a moment when it is not. I have written this code and I am not sure what is wrong because output is [1] when it should be [1, 3, 4, 5, 6, 7]. It is probably small error, but I have none to ask..
def check_order(a):
i = 0
while i < (len(a)-1):
b = []
if a[i] < a[(i + 1)]:
b.insert(i, a[i])
i = i + 1
return b
else:
break
a = [1, 3, 4, 5, 6, 7, 22, 10]
print(check_order(a))

There are 2 issues, you are redefining b on every loop, and also returning early inside the if statement
def check_order(a):
i = 0
b = []
while i < (len(a) - 1):
if a[i] < a[(i + 1)]:
b.insert(i, a[i])
i = i + 1
else:
break
return b

I think you need to understand what will happen return statement is called.
when you call the return statement the flow will return to the function calling the place
So during the first loop it self when it comes 8th line control will come back to 11th line . So output is only 1
so you can change something like below
def check_order(a):
i = 0
b = []
while i < (len(a) - 1):
if a[i] < a[(i + 1)]:
b.insert(i, a[i])
i = i + 1
else:
break
return b
a = [1, 3, 4, 5, 6, 7, 22, 10]
print(check_order(a))
Here we have return at end of while loop , So the control from return will come to function call at end of while loop

Related

using recursion to find the integer appearing odd times

I am looking for some guidance with the following code please. I am learning Python and I come from Java and C# where I was a beginner. I want to write a function which returns the number which appears an odd number of times. Assumption is that the array is always greater than 1 and there is always only one integer appearing an odd number of times. I want to use recursion.
The function does not return a value as when I store the result I get a NoneType. Please, I am not looking for a solution but some advice of where to look and how to think when debugging.
def find_it(seq):
seqSort = seq
seqSort.sort()
def recurfinder(arg,start,end):
seqSort = arg
start = 0
end = seqSort.length()-1
for i in range(start,end):
counter = 1
pos = 0
if seqSort[i+1] == seqSort[i]:
counter+=1
pos = counter -1
else:
if(counter % 2 == 0):
recurfinder(seqSort, pos+1, end)
else:
return seqSort[i]
return -1
You need to actually call recurFinder from somewhere outside of recurFinder to get the ball rolling.
def getOddOccurrence(arr, arr_size):
for i in range(0, arr_size):
count = 0
for j in range(0, arr_size):
if arr[i] == arr[j]:
count+= 1
if (count % 2 != 0):
return arr[i]
return -1
arr = [2, 3, 5, 4, 5, 2, 4, 3, 5, 2, 4, 4, 2 ]
n = len(arr)
print(getOddOccurrence(arr, n))
This answer uses recursion and a dict for fast counter lookups -
def find_it(a = [], i = 0, d = {}):
if i >= len(a):
return [ n for (n, count) in d.items() if count % 2 == 1 ]
else:
d = d.copy()
d[a[i]] = d.get(a[i], 0) + 1
return find_it(a, i + 1, d)
It works like this -
print(find_it([ 1, 2, 2, 2, 3, 3, 4, 5, 5, 5, 5 ]))
# [ 1, 2, 4 ]
print(find_it([ 1, 2, 3 ]))
# [ 1, 2, 3 ]
print(find_it([ 1, 1, 2, 2, 3, 3 ]))
# []
print(find_it([]))
# []
Above i and d are exposed at the call-site. Additionally, because we're relying on Python's default arguments, we have to call d.copy() to avoid mutating d. Using an inner loop mitigates both issues -
def find_it(a = []):
def loop(i, d):
if i >= len(a):
return [ n for (n, count) in d.items() if count % 2 == 1 ]
else:
d = d.copy()
d[a[i]] = d.get(a[i], 0) + 1
return loop(i + 1, d)
return loop(0, {})
It works the same as above.

IndexError: list index out of range when using variabel to indexing

def adjacentElementsProduct(inputArray):
i = 0
n = []
t = int(0)
b = int(1)
while i < len(inputArray):
noob = inputArray[t] * inputArray[b]
t += 1
b += 1
i += 1
n.append(noob)
return n
print(adjacentElementsProduct([3, 6, -2, -5, 7, 3]))
Can some one help me when I try to execute this its return
IndexError: list index out of range
Sorry for my bad English Grammar
You need to change your loop so that i only iterates up to len(inputArray) - 1.
Like this:
def adjacentElementsProduct(inputArray):
i = 0
n = []
t = 0
b = 1
while i < len(inputArray) - 1:
noob = inputArray[t] * inputArray[b]
t += 1
b += 1
i += 1
n.append(noob)
return n
print(adjacentElementsProduct([3, 6, -2, -5, 7, 3]))
This is because your noob array is essentially just each adjacent pair of elements in inputArray. Naturally, the number of pairs in a list of i elements is i - 1. This means that you need to change your loop to stop one iteration before, as it's throwing the IndexError when t is the len(inputArray) - 1 and b is the len(inputArray) (b isn't a valid value in the last iteration of your current code as there's not that many elements).
Here you set i=0, t=0, and b=1, thus your b always greater than i by 1. So, in the last loop (where t and i should equal len(inputArray) -1), the value of b should be len(inputArray) which is bigger than the length of your array.
I am not very sure about your excepted output, but I guess you could fix it like following:
while i < len(inputArray) - 1:
noob = inputArray[t] * inputArray[b]
t += 1
b += 1
i += 1
n.append(noob)
You can change the while loop for a for loop and use try / except to return the result when it reaches the end of the iteration. You can also add in extra except clauses to catch other errors and make use of else and finally if needs be .. https://docs.python.org/3/tutorial/errors.html
def adjacentElementsProduct(inputArray):
i = 0
n = []
t = int(0)
b = int(1)
for i in range(len(inputArray)):
try:
noob = inputArray[t] * inputArray[b]
t += 1
b += 1
i += 1
n.append(noob)
except IndexError:
return n
return n
print(adjacentElementsProduct([3, 6, -2, -5, 7, 3]))
l=[3, 6, -2, -5, 7, 3]
print([x*y for x,y in zip(l,l[1:])])
Here zip is used to create the adjacency pair

Confusion about variables in python

I am trying to implement heapsort but I am getting unexpected results. I think this is due to something I don't understand about how Python handles variables (I am talking about side effects). Here's the code:
from math import *
def parent(i):
return floor((i+1)/2)-1
def left(i):
return 2*i+1
def right(i):
return 2*i+2
def maxheapify(A, i):
l = left(i)
r = right(i)
if l < len(A) and A[i] < A[l]:
largest = l
else:
largest = i
if r < len(A) and A[largest] < A[r]:
largest = r
if largest != i:
temp = A[i]
A[i] = A[largest]
A[largest] = temp
maxheapify(A, largest)
def buildmaxheap(A):
for i in range(int(floor(len(A)/2)), -1, -1):
maxheapify(A, i)
def heapsort(A):
n = len(A)
buildmaxheap(A)
for k in range(len(A), 0, -1):
temp = A[0]
A[0] = A[k-1]
A[k-1] = temp
C = A[0:k-1]
maxheapify(C, 0)
A = C + A[k-1:n]
print(A)
Now when I run
A = [2, 4, 1, 3, 7, 5, 9]
heapsort(A)
print(A)
I obtain two printed lines (one from inside the heapsort showing that the sorting worked and one from the last print):
[1, 2, 3, 4, 5, 7, 9]
[1, 7, 5, 3, 4, 2, 9]
Obviously, I'd like them both to be the same (which would mean that the sorting actually worked and A is sorted after calling heapsort(A))
So what I don't get is:
If A is correctly sorted (at the point of the last line in heapsort(A)), why doesn't this change persist after leaving the function block?
If this is due to some permanence of the variable A, why isn't the end result the original value of A, but the intermediate step in heapsort, which is the result of the maxheapify call?
At the start of the function, the list A inside the function is the same as the list outside of the function, and any modifications made to one will be reflected in the other (it's a mutable object).
When you do an assignment to a list, you're substituting a new list object for the old list object. This breaks the connection to the outside object.
Instead of assigning a new list to A, you can assign to a slice of A and the original object will be modified in place instead.
A[:] = C + A[k-1:n]
A = C + A[k-1:n]
This is the line responsible for the behaviour you're seeing. By setting A equal to A[0:k-1] + A[k-1:n] you are making a copy of all of A's elements. If you want your changes to persist within the list you passed in you must assign the list to all the elements of A like so:
A[:] = C + A[k-1:n]
The following implementation shows a rewrite of your code but includes an alternate solution above the last call to the print function. The commented-out line may replace the line directly above it, or you may choose to return a at the end of the heap_sort function and rebind the value of a in your main function instead.
def main():
a = [2, 4, 1, 3, 7, 5, 9]
heap_sort(a)
print(a)
parent = lambda i: (i + 1 >> 1) - 1
left = lambda i: (i << 1) + 1
right = lambda i: i + 1 << 1
def max_heapify(a, i, n):
l = left(i)
r = right(i)
largest = l if l < n and a[i] < a[l] else i
if r < n and a[largest] < a[r]:
largest = r
if largest != i:
a[i], a[largest] = a[largest], a[i]
max_heapify(a, largest, n)
def build_max_heap(a, n):
for i in reversed(range(n + 2 >> 1)):
max_heapify(a, i, n)
def heap_sort(a):
n = len(a)
build_max_heap(a, n)
for k in reversed(range(n)):
a[0], a[k] = a[k], a[0]
c = a[:k]
max_heapify(c, 0, k)
a[:k] = c
# the following would change "a" in this scope only
# a = c + a[k:]
# print(a)
if __name__ == '__main__':
main()

Fill in an array using loop with multiple variables (new to Python, old to C++ (back in the day))

Basically what I want to do is create something like this in python (this is basic idea and not actual code):
n = 3
i = n + 1
a = [1, 3, 3, 1]
b = [1, 2, 1]
while n > 1:
Check if n is even
- if n is even, then for all i in range(0,n), insert values into an array using the formula below
- b[n-i] = a[n-i-1] + a[n-i], this value will replace the previously given value of b[] above the code.
- Print out the array
- After each area is filled, n+=1, i=n+1 are applied, then the loop continues
Check if n is odd
- same process except formula is
- a[n-i] = b[n-i-1] + a[n-i], this value will replace the previously given value of a[] above the code.
- Print out the array
- After each area is filled, n+=1, i=n+1 are applied, then the loop continues
This process will loop and print each and continue on, the arrays will essentially look like this:
b = [1, 4, 6, 4, 1], a = [1 5, 10, 10, 5, 1], b = [1, 6, 15, 20, 20, 15, 6, 1], etc.
Here is the code that I currently have, however I'm getting an 'out of range' error.
n = 3
i = n + 1
b = [1, 2, 1]
a = [1, 3, 3, 1]
while n > 1:
if n%2==0:
print("even")
for i in range(0,n):
b[n-i].append(a[n-i-1]+a[n-i])
else:
print("odd")
for i in range(0,n):
print("yay")
a[n-i].append(b[n-i-1]+b[n-i])
if n%2==0:
print(b)
else:
print(a)
n +=1
i = n + 1
print("loop")
The random prints throughout the code are to test and see if it is even making it into the process. There were from a previous code and I just haven't removed them yet.
Hopefully you can help me, I can't find anything online about a loop that constantly increases the size of an array and fills it at the same time.
Sorry struggling with the code that's in the sample. From your description I can see that you want to generate Pascal's triangle. Here's a short snippet that will do this.
a = [1, 1]
for _ in range(10):
a = [1] + [x+y for (x,y) in zip(a[:-1], a[1:])] + [1]
print a
a[:-1] refers to the whole array except the last element and a[1:] refers to whole array except first element. zip combines first elements from each array into a tuple and so on. All that remains is to add them and pad the row with ones one the outside. _ is used to tell Python, I don't care about this variable - useful if you want to be explicit that you are not using the range value for anything except flow control.
Maria's answer is perfect, I think. If you want to start with your code, you can rewrite your code as below to get similar result. FYI.
n = 3
b = [1, 2, 1]
while 1 < n < 10:
if n % 2 == 0:
print("even")
b = [0] * (n + 1)
for i in range(0, n + 1):
if i == 0:
b[i] = a[0]
elif i == n:
b[i] = a[i - 1]
else:
b[n - i] = a[i - 1] + a[i]
else:
print("odd")
a = [0] * (n + 1)
for i in range(0, n + 1):
if i == 0:
a[i] = b[0]
elif i == n:
a[i] = b[i - 1]
else:
a[i] = b[i - 1] + b[i]
if n % 2 == 0:
print(b)
else:
print(a)
n += 1
print("loop")

Find the number of consecutively increasing elements in a list

I got a problem in TalentBuddy, which sounds like this
A student's performance in lab activities should always improve, but that is not always the case.
Since progress is one of the most important metrics for a student, let’s write a program that computes the longest period of increasing performance for any given student.
For example, if his grades for all lab activities in a course are: 9, 7, 8, 2, 5, 5, 8, 7 then the longest period would be 4 consecutive labs (2, 5, 5, 8).
So far, I seem too confused to work the code. The only thing that I worked is
def longest_improvement(grades):
res = 0
for i in xrange(len(grades) - 2):
while grades[i] <= grades[i + 1]:
res += 1
i += 1
print res
But that prints 17, rather than 6 when grades = [1, 7, 2, 5, 6, 9, 11, 11, 1, 6, 1].
How to work out the rest of the code? Thanks
Solved with some old-fashioned tail-recursion:
grades = [1, 7, 2, 5, 6, 9, 11, 11, 1, 6, 1]
def streak(grades):
def streak_rec(longest, challenger, previous, rest):
if rest == []: # Base case
return max(longest, challenger)
elif previous <= rest[0]: # Streak continues
return streak_rec(longest, challenger + 1, rest[0], rest[1:])
else: # Streak is reset
return streak_rec(max(longest, challenger), 1, rest[0], rest[1:])
return streak_rec(0, 0, 0, grades)
print streak(grades) # => 6
print streak([2]) # => 1
Since the current solution involves yield and maps and additional memory overhead, it's probably a good idea to at least mention the simple solution:
def length_of_longest_sublist(lst):
max_length, cur_length = 1, 1
prev_val = lst[0]
for val in lst[1:]:
if val >= prev_val :
cur_length += 1
else:
max_length = max(max_length, cur_length)
cur_length = 1
prev_val = val
return max(max_length, cur_length)
We could reduce that code by getting the previous value directly:
def length_of_longest_sublist2(lst):
max_length, cur_length = int(bool(lst)), int(bool(lst))
for prev_val, val in zip(lst, lst[1:]):
if val >= prev_val:
cur_length += 1
else:
max_length = max(max_length, cur_length)
cur_length = 1
return max(max_length, cur_length)
which is a nice trick to know (and allows it to easily return the right result for an empty list), but confusing to people who don't know the idiom.
This method uses fairly basic python and the return statement can be quickly modified so that you have a list of all the streak lengths.
def longest_streak(grades):
if len(grades) < 2:
return len(grades)
else:
start, streaks = -1, []
for idx, (x, y) in enumerate(zip(grades, grades[1:])):
if x > y:
streaks.append(idx - start)
start = idx
else:
streaks.append(idx - start + 1)
return max(streaks)
I would solve it this way:
from itertools import groupby
from funcy import pairwise, ilen
def streak(grades):
if len(grades) <= 1:
return len(grades)
orders = (x <= y for x, y in pairwise(grades))
return max(ilen(l) for asc, l in groupby(orders) if asc) + 1
Very explicit: orders is an iterator of Trues for ascending pairs and Falses for descending ones. Then we need just find a longest list of ascending and add 1.
You're using the same res variable in each iteration of the inner while loop. You probably want to reset it, and keep the highest intermediate result in a different variable.
Little bit late, but here's my Updated version:
from funcy import ilen, ireductions
def streak(last, x):
if last and x >= last[-1]:
last.append(x)
return last
return [x]
def longest_streak(grades):
xs = map(ilen, ireductions(streak, grades, None))
return xs and max(xs) or 1
grades = [1, 7, 2, 5, 6, 9, 11, 11, 1, 6, 1]
print longest_streak(grades)
print longest_streak([2])
I decided in the end to not only produce a correct
version without bugs, but to use a library I quite like funcy :)
Output:
6
1
Maybe not as efficient as previous answers, but it's short :P
diffgrades = np.diff(grades)
maxlen = max([len(list(g)) for k,g in groupby(diffgrades, lambda x: x >= 0) if k]) + 1
Building on the idea of #M4rtini to use itertools.groupby.
def longest_streak(grades):
from itertools import groupby
if len(grade) > 1:
streak = [x <= y for x, y in zip(grades,grades[1:])]
return max([sum(g, 1) for k, g in groupby(streak) if k])
else:
return len(grades)

Categories