Python List IndexError: list index out of range - python

I try to search in an list the maximal frequency of an element.
Now I have the problem that the last checked element of the list (a[i+1]) I get an IndexError. How can I solve this problem?
With len(a)-1 the last element a[i+1] is never used thus the result of maxMode(a4) is wrong.
a1 = [5,3,6,7,2,7,3,6,2,8,7]
a2 = [5,3,6,7,2,7,3,6,2,8,7,5,2]
a3 = [5,3,6,7,2,7,3,6,2,8,2,5,2]
a4 = [5,3,6,7,2,7,3,6,2,7,2,5,1]
def maxMode(a):
cnt = 1
maxCnt = 0
res = 0
for i in range(len(a)-1):
if a[i] == a[i+1]:
cnt += 1
else:
if cnt >= maxCnt:
maxCnt = cnt
res = a[i]
cnt = 1
return res
a1.sort()
a2.sort()
a3.sort()
a4.sort()
print(a1)
print(maxMode(a1))
print(a2)
print(maxMode(a2))
print(a3)
print(maxMode(a3))
print(a4)
print(maxMode(a4))

As BluCode points out, your code runs fine for the 4 test cases you provide (or at least, it doesn't crash and returns a mode although as you point out, for the 4th test, it's not the max mode). Also, as you alluded to, you're not counting your last element (or really, you're not checking if the last batch could be the maximal), and so if a4 was instead: [1, 2, 2, 2, 3, 3, 5, 5, 6, 6, 7, 7, 7, 7], it wrongly prints out 2 (because it finds 3 2's and 3 7's and doesn't do a final check for the 7s being as good or better)
The following worked with my 4 updated test cases:
a1 = [5,3,6,7,2,7,3,6,2,8,7]
a2 = [5,3,6,7,2,7,3,6,2,8,7,5,2]
a3 = [5,3,6,7,2,7,3,6,2,8,2,5,2]
a4 = [5,3,6,7,2,7,3,6,2,7,2,5,1,7]
def maxMode(a):
cnt = 1
maxCnt = 0
res = 0
for i in range(len(a)-1):
if a[i] == a[i+1]:
cnt += 1
else:
if cnt >= maxCnt:
maxCnt = cnt
res = a[i]
cnt = 1
if cnt >= maxCnt:
maxCnt = cnt
res = a[i]
return res
a1.sort()
a2.sort()
a3.sort()
a4.sort()
print(a1)
print(maxMode(a1))
print(a2)
print(maxMode(a2))
print(a3)
print(maxMode(a3))
print(a4)
print(maxMode(a4))

Related

How to print first and last index of the longest sequence of same-values neighbors?

I am interested in finding the first and last index of the longest sequence of same-valued neighbours for a given list. The closest question I could find was: First and last index of a sequence, but this does not exactly answer my question.
So let's say for example:
a = [4, 6, 1, 0, 0, 0, 2, 4, 4, 1]
I would like to output to be
[3, 5]
Here is what I have come up with so far, and it works for this example. However, once the list changes to have a 0 somewhere before or after the sequence (non-neighbouring) it does not work anymore.
# Find distinct values of a
distinct = []
for x in a:
if x not in distinct:
distinct.append(x)
# Check which value has the longest sequence
countMax = 0
countNow = 1
num = 0
for i in a:
if a[i] == a[i+1]:
countNow += 1
num = i
else:
countNow = 1
if countNow > countMax:
countMax = countNow
longest = distinct[num-1]
# Find first index value of number with longest sequence
firstIndex = a.index(longest)
# Find last index value of number with longest sequence
a_reverse = a[::-1]
firstIndex_reverse = a_reverse.index(longest)
lastIndex = len(a) - 1 - firstIndex_reverse
print(firstIndex, lastIndex)
I don't know how better to find the first and last index for only the sequence in question.
I'd just iterate the list and keep track of everything:
a = [4, 6, 1, 0, 0, 0, 2, 4, 4, 4, 4, 4, 4, 1]
# indices
best_start = 0
best_end = 0
curr_start = 0
curr_end = 0
prev_val = a[0]
for (idx, curr_val) in enumerate(a[1:]):
curr_end = idx + 1 # +1 since slicing shifted everything
if prev_val == curr_val:
if curr_end - curr_start > best_end - best_start:
best_start = curr_start
best_end = curr_end
else:
curr_start = curr_end
prev_val = curr_val
print(best_start, best_end)

Python: I cannot get the right Merge Sort

I wrote the following programming; after running it, the result is not correct.
So what is wrong with my code?
def mergesort(list1):
if len(list1) > 1:
mid = len(list1) // 2
left_list = list1[:mid]
right_list = list1[mid:]
mergesort(left_list)
mergesort(right_list)
i = 0 # left
j = 0 # right
k = 0 # total
while len(list1) > 1 and i < len(left_list) and j < len(right_list):
if left_list[i] < right_list[j]:
list1[k] = left_list[i]
k += 1
i +=1
else:
list1[k] = right_list[i]
k += 1
j += 1
if len(list1) > 1 and i < len(left_list):
list1[k] = left_list[i]
i += 1
k += 1
if len(list1) > 1 and j < len(right_list):
list1[k] = right_list[j]
k += 1
j += 1
return list1
ex = [3, 5, 9, 0, 8, 7]
mergesort(ex)
result: [0, 3, 5, 7, 7, 9]
I found three problems
you didn't get result from mergesort(left_list) mergesort(right_list) (but this could even work because it replaces values in original list)
you used i instead of j in one place
you used if istead of while in two places
def mergesort(list1):
if len(list1) > 1:
mid = len(list1) // 2
left_list = list1[:mid]
right_list = list1[mid:]
left_list = mergesort(left_list) # 1. get result
right_list = mergesort(right_list) # 1. get result
i = 0 # left
j = 0 # right
k = 0 # total
while len(list1) > 1 and i < len(left_list) and j < len(right_list):
if left_list[i] < right_list[j]:
list1[k] = left_list[i]
k += 1
i +=1
else:
list1[k] = right_list[j] # 2. use `j` instead of `i`
k += 1
j += 1
while len(list1) > 1 and i < len(left_list): # 3. use `while`
list1[k] = left_list[i]
i += 1
k += 1
while len(list1) > 1 and j < len(right_list): # 3. use `while`
list1[k] = right_list[j]
k += 1
j += 1
return list1
ex = [3, 5, 9, 0, 8, 7]
print(mergesort(ex))
There are 3 distinct steps in merge sort: the base case, the recursive step, and the merge step. The merge step is often written as a separate function, but here I have incorporated it into the merge_sort function to stay consistent with your code. Your biggest problem was that you did not take you recursively-sorted sub-lists and merge them.
def mergesort(list1):
#base case
if len(list1) <= 1:
return list1
#recursive step
mid = len(list1) // 2
left_list = list1[:mid]
right_list = list1[mid:]
sorted_left = mergesort(left_list)
sorted_right = mergesort(right_list)
#merge step
result = []
while len(sorted_left) > 0 and len(sorted_right) > 0:
if sorted_left[0] <= sorted_right[0]:
result.append(sorted_left.pop(0))
elif sorted_right[0] <= sorted_left[0]:
result.append(sorted_right.pop(0))
else:
result.append(sorted_left.pop(0))
result.append(sorted_right.pop(0))
result = result + sorted_left + sorted_right
return result
print(mergesort([3,5,1,9,7])) #output: [1, 3, 5, 7, 9]

Find out if this sequence is one in which the same numbers are in pairs, but there is one other number between the same numbers

I am total newbie in python who is practising right now with little 'algorithms'.
So here is my exercise:
N-number integers are given (user have to input). The task is to find out if this sequence is one in which the same numbers are in pairs, but there is one other number between the same numbers.
For example, for a sequence of 11 numbers 3 3 5 10 10 1 12 12 3 6 6, the answer is "yes" and for the sequence 2 2 3 15 15 4 4 8 4 4 1 the answer is "no".
Here's what I tried. But this gypsy-code is not working well:
n = int(input())
right_sequence = True
for i in range(n):
current = int(input())
if i > 0:
if current == previous:
if previous != current:
right_sequence = True
else:
right_sequence = False
previous = current
if right_sequence == True:
print('Yes')
else:
print('No')
I tried to use your own code as much as possible.
Basically the number of inputs should be at least 5. (The shortest correct answer would be in this format : A A B A A which has 5 input.
If we replace the i's with their remainder to 3. (i.e i % 3) Then the indexes for 8 input values would be:
0 1 2 0 1 2 0 1 ...
For which a correct answer would look like bellow:
A A B A A B A A ...
A correct list (The one that outputs "Yes") is the one that:
all the 0 indexes are different from their previous value (Except the first 0 which deosn't have previous value)
all the 1 indexes are equal to their previous value
all the 2 indexes are different from their previous value
The list ends with a 1 index
These 4 points are summarized into 4 if conditions in the bellow code. (The ones that have the value 'k' which carries the remainder of i'th to 3)
n = int(input())
right_sequence = True
k = 0
if n < 5:
right_sequence = False
for i in range(n):
current = int(input())
if i > 0:
k = i % 3
if k == 0:
if current == previous:
right_sequence = False # Print (No)
if k == 1:
if current != previous:
right_sequence = False # Print (No)
if k == 2:
if current == previous:
right_sequence = False # Print (No)
previous = current
if k != 1:
print('No')
elif right_sequence == True:
print('Yes')
elif right_sequence == False:
print('No')
You could slices and zip:
def f(l):
all(a == b != c for a, b, c in zip(x[::3], x[1::3], x[2::3]))
f([3, 3, 5, 10, 10, 1, 12, 12, 3, 6, 6])
# True
f([2, 2, 3, 15, 15, 4, 4, 8, 4, 4, 1])
# False
This will work only if the sequence starts with a pair and you might have to check special cases at the end, but it should hint in the right direction.
I have solved the issue the following way:
x = [2, 2, 3, 15, 15, 4, 4, 8, 4, 4, 1]
y = [3, 3, 5, 10, 10, 1, 12, 12, 6, 6]
def check_order(x):
for i in range(len(x)):
only_equal_in_row = True # all previous checked j index elements were equal to i
for j in range(i+1, len(x)):
if x[i] == x[j]:
if only_equal_in_row is False: # check if there was j not equal to i elements before
return False
else:
only_equal_in_row = False # found j element not equal to i
return True
if __name__ == "__main__":
print(check_order(x))
print(check_order(y))
Edit: Without functions due to OP request:
x = [2, 2, 3, 15, 15, 4, 4, 8, 4, 4, 1]
is_right = True
stop = False # need to stop outer for loop
for i in range(len(x)):
if stop:
break
only_equal_in_row = True # all previous checked j index elements were equal to i
for j in range(i+1, len(x)):
if x[i] == x[j]:
if only_equal_in_row is False: # check if there was j not equal to i elements before
is_right = False
stop = True
break
else:
only_equal_in_row = False # found j element not equal to i
print(is_right)

Two arrays sorted to see if they have the same value, but it only picks up that there are 2/3 values that are the same in the arrays

I don't know why only 2 out of 3 of values are showing that they are the same in my code, is there something I am missing?
def occurInBoth(B,A):
occured = 0
for i in range(len(A)):
if A[i] == B[i]:
occured += 1
return occured
A = [5,12,31,7,25]
sorted(A)
A.sort()
print(A)
B = [4,12,7,31,42,8]
sorted(B)
B.sort()
print(B)
occured = occurInBoth(B,A)
print(occured)
Could you please advise me?
There is a logical error in your algorithm. If two lists are sorted, that does not mean that the items will occur at the same index.
Indeed, take the sorted lists in your example:
A = [5, 7, 12, 25, 31]
B = [4, 7, 8, 12, 31, 42]
As you can see 12 occurs in both lists, but not at the same index.
You can however make use of the fact that the lists are sorted:
def occurInBoth(a, b):
occured = i = j = 0
while i < len(a) and j < len(b):
if a[i] < b[j]:
i += 1
elif a[i] > b[j]:
j += 1
else:
occurred += 1
i += 1
j += 1

Algorithm to find # elements less than target in a sorted Matrix in O(n)?

Design an algorithm that outputs the number of entries in A that are smaller than or equal to x. Your algorithm should run in O(n) time.
For example in the array below if my target was '5' then I would return 2 b/c 1 and 3 are smaller.
[1, 3, 5]
[2, 6, 9]
[3, 6, 10]
I gave it a shot with the code below which is close to working and I think it's O(n) ... the problem I see is if I don't have the # in my array I am not sure if I am returning the right value?
def findLessX(m,n,x):
i = 0
j = n-1
while (i < n and j >= 0):
if i == n or j == n:
print("n not found")
return (i+1)*(j+1)-1
if (m[i][j] == x):
print(" n Found at ", i , " ", j)
return (i+1)*(j+1)-1
elif (m[i][j] > x):
print(" Moving left one column")
j = j - 1
elif (m[i][j] < x):
print(" Moving down one row")
i = i + 1
print(" n Element not found so return max")
return (i)*(j+1)
# Driver code
x = 5
n = 3
m = [ [1, 3, 5],
[2, 6, 9],
[3, 6, 9]]
print("Count=", findLessX(m, n, x))
Inspect the Count and simple matrix above to see if soln works ~
If both columns and rows are sorted ascending, then for any given border value some stairs line does exist. It divides matrix into two parts - higher (and equal) and lower than border value. That line always goes left and down (if traversal starts from top right corner).
[1, 3, |5]
____|
[2,| 6, 9]
[3,| 6, 10]
So scan from top right corner, find starting cell for that line on the right or top edge, then follow the line, counting elements being left to it.
Complexity is linear, because line never turns back.
P.P.S. I hoped that you could write code with given clues
def countLessX(m,n,x):
col = n-1
count = 0
for row in range(n):
while (col >= 0) and (m[row] [col] >= x):
col = col - 1
count = count + col + 1
if col < 0: #early stop for loop
break
return count
# Driver code
n = 3
m = [ [1, 3, 5],
[2, 6, 9],
[3, 6, 9]]
for x in range(11):
print("x=", x, "Count=", countLessX(m, n, x))
x= 0 Count= 0
x= 1 Count= 0
x= 2 Count= 1
x= 3 Count= 2
x= 4 Count= 4
x= 5 Count= 4
x= 6 Count= 5
x= 7 Count= 7
x= 8 Count= 7
x= 9 Count= 7
x= 10 Count= 9
As mentioned in my comment your problem is not solveable in O(n) for most matrices. Some other thoughts:
Why count j downwards?
i and j can never become n
Here is a solution in O(n) that perhaps fullfills your needs.
Here is the adapted code:
def findLessX(m,n,x):
i = 0
j = 0
while True:
if i+1<n and m[i+1][j]<x:
i=i+1
elif j+1<n and m[i][j+1]<x:
j=j+1
else:
print("n found at ", i+1 , " ", j+1, "or element not found so return max")
return (i+1)*(j+1)
Both answers suggested above will result in O(n^2).
In worst case, the algorithms will inspect all n^2 elements in the matrix.

Categories

Resources