Non-decreasing Array List Index out of Range - python

This is a coding challenge from Daily Interview Pro where you are given an array in arbitrary order, and you have to make it an increasing array with 1 modification to the array or less. This is my code:
def check(lst):
count = 0
for i in lst:
if i == lst[-1]:
break
**if i > lst[i+1]:**
count += 1
if count <= 1:
return True
else:
return False
check([13, 4, 7])
#Should return True
The Error is where the stars are. Error: list index out of range. I do not understand this error because I made an if statement for the for loop to break when the for loop gets to the last number. (I have made my indenting correctly, the stars make it look like the indenting is off)

I checked and the value of 'i' is 13 and your list is only if len 3. The value of 'i' depends on the value at the list index. That's why it is giving an error

In your example, the counter i iterates through your list elements - first it becomes 13, then 4, and last 7.
So, when you say lst[i+1], it becomes lst[13+1] == lst[14], which does not exist in your lst, since it goes from lst[0] up to lst[2].
I think you probably mean to iterate using range:
for i in range(len(lst)):
...

Related

Count the unique elements in a list without set

I am currently attempting to make a program that will count and print the number of unique elements in a list.
My code:
def solution(N, A):
yee = 1
for i in range(1, len(A)):
j = 0
for j in range(i):
if(A[i] == A[j]):
yee-=1
if(i==j+1):
yee +=1
print(yee)
N = int(input())
A = []
n = 0
for e in input().split():
if(n<N):
A.append(int(e))
n+=1
solution(N, A)
With the list containing (1 2 3 1 4 2 5 6 7 8) the output is supposed to be 6. However, my program is returning 8. I believe this is due to the program counting the 1 and 2, even though they are not technically unique in the problem. I'm sure it's and easy fix, but I just can't seem to figure it out. Any help would be greatly appreciated!!
The only way you would get the output of 6 for (1, 2, 3, 1, 4, 2, 5, 6, 7, 8) would be if you wanted to count the number of elements that appear exactly once, as opposed to the number of unique elements (there are 8 elements, of which two are repeated more than once).
You could do this in a one-liner:
def num_single_elements(A):
return len(list(e for e in A if A.count(e) == 1))
Similarly if you need to keep check of the number of elements further on in your code, I like dictionary comprehension for this kind of problem:
dict_A = {x:A.count(x) for x in A}
print(len([x for x in dict_A if dict_A[x] == 1]))
As Green Cloak Guy said, you seem to be looking for the number of elements which appear exactly once, and his answer contains a solution to that. Here's a simple solution for finding the number of unique elements:
def unique_elements(A):
return len([ 1 for (index, a) in enumerate(A) if A.index(a) == index ])
The idea here is to count up the first occurrence of each unique value.
enumerate allows us to get the index of the item, as well as the item itself, as we iterate;
A.index(a) gives the index of the first time the value of a appears in A.
So, if we count up all the times index equals A.index(a), we're counting the first time an item appears which has never appeared before, which is equal to the number of unique elements.

My question is about a code i have described but it didn't work

SUMMER OF '69: Return the sum of the numbers in the array, except ignore sections of numbers starting with a 6 and extending to the next 9 (every 6 will be followed by at least one 9). Return 0 for no numbers.ΒΆ
I have tried to use the pop method but it didn't work. I want to know why.
def summer_69(arr):
num=(6,7,8,9)
if num not in arr:
return sum(arr)
if num in arr:
arr.pop(num)
return sum(arr)
print(summer_69([4,5,6,7,8,9]))
I am getting the whole sum like in this one I am getting like 39.
Pop removes the item at a specified index. Max index in your array is 5 (4 has index 0).
I recommend finding the index of 6 via
arr.index(6)
Not efficient, but you can then repeatedly pop that index until it becomes 9, (and popping once more if "extending to" means including the 9).
Instead of doing this i will suggest you to use a single loop as it will be more efficient. Use single loop and keep adding number to sum until 6 is encountered. As soon as 6 comes skip the numbers till a 9 occurs. Again start to add numbers to sum. Runs in O(n).
i=0
Sum =0
While i < length:
If a[i] == 6:
While i < length and a[i] != 9:
i += 1
Else:
Sum += a[i]
i += 1
return Sum

How to update array Index in loop (IndexError: list index out of range)

I should not use advance function, as this is a logical test during interview.
Trying to remove all digits which appear more than once in array.
testcase:
a=[1,1,2,3,2,4,5,6,7]
code:
def dup(a):
i=0
arraySize = len(a)
print(arraySize)
while i < arraySize:
#print("1 = ",arraySize)
k=i+1
for k in range(k,arraySize):
if a[i] == a[k]:
a.remove(a[k])
arraySize -= 1
#print("2 = ",arraySize)
i += 1
print(a)
result should be : 1,2,3,4,5,6,7
But i keep getting index out of range. i know that it is because the array list inside the loop changed, so the "while" initial index is different with the new index.
The question is : any way to sync the new index length (array inside the loop) with the parent loop (index in "while" loop) ?
The only thing i can think of is to use function inside the loop.
any hint?
Re-Calculating Array Size Per Iteration
It looks like we have a couple issues here. The first issue is that you can't update the "stop" value in your inner loop (the range function). So first off, let's remove that and use another while loop to give us the ability to re-calculate our array size every iteration.
Re-Checking Values Shifted Into Removed List Spot
Next, after you fix that you will run into a larger issue. When you use remove it moves a value from the end of the list or shifts the entire list to the left to use the removed spot, and you are not re-checking the value that got moved into the old values removed spot. To resolve this, we need to decrement i whenever we remove an element, this makes sure we are checking the value that gets placed into the removed elements spot.
remove vs del
You should use del over remove in this case. remove iterates over the list and removes the first occurrence of the value and it looks like we already know the exact index of the value we want to remove. remove might work, but it's usage here over complicates things a bit.
Functional Code with Minimal Changeset
def dup(a):
i = 0
arraySize = len(a)
print(arraySize)
while i < arraySize:
k = i + 1
while k < arraySize: # CHANGE: use a while loop to have greater control over the array size.
if a[i] == a[k]:
print("Duplicate found at indexes %d and %d." % (i, k))
del a[i] # CHANGE: used del instead of remove.
i -= 1 # CHANGE: you need to recheck the new value that got placed into the old removed spot.
arraySize -= 1
break
k += 1
i += 1
return a
Now, I'd like to note that we have some readability and maintainability issues with the code above. Iterating through an array and manipulating the iterator in the way we are doing is a bit messy and could be prone to simple mistakes. Below are a couple ways I'd implement this problem in a more readable and maintainable manner.
Simple Readable Alternative
def remove_duplicates(old_numbers):
""" Simple/naive implementation to remove duplicate numbers from a list of numbers. """
new_numbers = []
for old_number in old_numbers:
is_duplicate = False
for new_number in new_numbers:
if old_number == new_number:
is_duplicate = True
if is_duplicate == False:
new_numbers.append(old_number)
return new_numbers
Optimized Low Level Alternative
def remove_duplicates(numbers):
""" Removes all duplicates in the list of numbers in place. """
for i in range(len(numbers) - 1, -1, -1):
for k in range(i, -1, -1):
if i != k and numbers[i] == numbers[k]:
print("Duplicate found. Removing number at index: %d" % i)
del numbers[i]
break
return numbers
You could copy contents in another list and remove duplicates from that and return the list. For example:
duplicate = a.copy()
f = 0
for j in range(len(a)):
for i in range(len(duplicate)):
if i < len(duplicate):
if a[j] == duplicate[i]:
f = f+1
if f > 1:
f = 0
duplicate.remove(duplicate[i])
f=0
print(duplicate)

List index out of range error while performing a binary search

I attempted to create a function that takes an ordered list of numbers and a given number, and decides whether or not the given number is inside the list. I am trying to use a binary search to accomplish this task.
I have two steps:
First, I am making list1 smaller by only taking the numbers in list1 that are smaller than the given number, and then appending those numbers into a new list, called newlist.
Next, in the while loop, I am basically taking all the numbers that are less than the number in the middle of the newlist and removing them, repeating that process multiple times until there is only one number in newlist. From there, I would compare that number to the given number. My code is shown below.
list1 = [1, 3, 5, 6, 8, 14, 17, 29, 31]
number = 7
def func(list1, number):
newlist = []
for x in list1:
if x < number:
newlist.append(x)
else:
continue
while len(newlist) > 1:
for x in range(0, len(newlist) - 1):
if newlist[x] < newlist[round(len(newlist) / 2)]:
newlist.remove(newlist[x])
else:
continue
if newlist[0] == number:
return True
else:
return False
print(func(list1, number))
I am receiving an error at line 36 (if newlist[x] < newlist[round(len(newlist) / 2)]:), that the list index is out of range. I think that the problem is that as newlist is getting smaller and smaller, the x value set by range(0, len(newlist) - 1) is staying the same?? If that is the case, I am unsure of how to remedy that. Much thanks in advance.
The issue is this bit right here:
for x in range(0, len(newlist) - 1):
if newlist[x] < newlist[round(len(newlist) / 2)]:
newlist.remove(newlist[x])
First, you're iterating over the list
[0, 1, 2, ..., len(newlist) - 1]
This list is generated when you start the loop, meaning that if len(newlist) is 7 at the beginning, the list will always go up to 6, regardless of whether things are removed from newlist, which you later do. This is what causes your error, since at some point you've removed enough elements that your list is now, say, three elements large, but python is trying to access the fifth element because the list it's iterating over isn't newlist, it's [0, 1, 2, 3, 4, 5, 6].
To fix this, you could (for example) replace the for loop with this:
x = 0
while x < len(newlist - 1):
if newlist[x] < newlist[round(len(newlist) / 2)]:
newlist.pop(x) # simple way of saying "remove item at index x"
This is essentially the way of doing a C or Java-style for loop in python, and will avoid this type of problem.
I also understand that you have an issue with the logic in your code, which was pointed out in one of the comments above and gets more to the heart of your underlying issue, but this is at least an explanation of why this error occurred in the first place, so maybe it's helpful to you in the future

Why is this Python code for finding the mode of function not working?

lst = [3, 4, 3, 5, 3]
def lstmaker(lst):
lst1 = []
x = 0
while x < len(lst):
if lst[x] == lst[x+1]:
lst1.append(lst[x])
else:
pass
x+=1
print lst1
lstmaker(lst)
I tried to make this simple program to find the the mode of list, but it just throws the index of out range error.
Thanks
For the last value of x, lst[x+1] x+1 is out of range. The while loop should be while x < len(lst) -1.
As a side note, to calculate the mode, you can simply do: max(set(lst), key=lst.count) as shown here.
The logic is incorrect.
For starters, the reason you're getting an index out of range issue is because of the line
if lst[x] == lst[x+1]
x is correctly incremented throughout your loop, but when x is at the last index, that +1 bit accesses an index that isn't in the list (e.g. index 5 of a list of size 5).
Additionally, what you were actually doing within the loop doesn't appear to be getting you towards a value for the mode. The mode is the element(s) in a list that occurs the most. One approach to tackling this problem could be using a dictionary (dict()) where the "keys" are the elements in your list, and the "values" are the amount of times each element occurs.
Try something like this:
# lst defined up here
occurrences = dict()
for x in lst:
if x in occurrences:
occurrences[x] += 1
else:
occurrences[x] = 1
mode = occurrences.keys()[0]
for k in occurrences:
if occurrences[k] >= mode:
mode = k
print(mode) # or return, etc.
This is perhaps not the most "Pythonic" solution, though it is an intuitive break-down of the logic involved in finding the mode, at least as if you were to do it by hand on paper.

Categories

Resources