Rewrite insert() function - list index out of range - python

I'm essentially trying to re-create a version of the insert() function for a homework assignment.
I've written the following function:
def insert_value(my_list, value, insert_position):
list_copy = []
if insert_position < 0:
insert_position = 0
if insert_position >= len(my_list):
insert_position = len(my_list) - 1
i = 0
while i < len(my_list) + 1:
while i < insert_position:
list_copy.append(my_list[i])
i += 1
while i == insert_position:
list_copy.append(value)
i += 1
while i > insert_position:
list_copy.append(my_list[i-1])
i += 1
return list_copy
I get the error list index out of range for the final while sub-loop, and I can't work out why. The while loop is accounting for the new list length (while i < len(my_list) + 1). What am I missing?

Your problem is because you are using those nested while loops which do not exit until their condition is false. So the outer while loop check for i being less then the length of my_list doesn't happen until all nested while loops finish (which it never does). Specifically I think the issue is with the last while loop here:
while i > insert_position:
list_copy.append(my_list[i-1])
i += 1
This while loop will not end because i will always be greater then the insert_position and eventually the i value will be outside the length of your my_list.
If you change your code logic to use if statements inside the while loop I think that will be better and then you only have to increase i once at the end:
i = 0
while i < len(my_list) + 1:
if i < insert_position:
list_copy.append(my_list[i])
elif i == insert_position:
list_copy.append(value)
else:
list_copy.append(my_list[i-1])
i += 1

Related

Don't know why the loop doesn't work (Python)

I just recently started learning Python. Tried to solve a problem where you are given an array of integers and you need to find three of them with the sum closest to target.
My idea was to sort the array and then create two pointers - one at the start of the array, moving right, and one at the end of the array, moving left. And the third pointer is supposed to move along the entire array, while the program calculates and uses the sum of all three of them. But it doesn't work. It ignores some of the indexes.
I feel like if I don't understand this I'll never understand loops in general.
nums = [0,1,1,1]
target = 100
nums.sort()
pointer_one = 0
pointer_two = len(nums) - 1
result = nums[0] + nums[1] + nums[2]
while pointer_one < pointer_two:
for i in nums:
if i == pointer_one or i == pointer_two:
pass
else:
sum_num = nums[i] + nums[pointer_one] + nums[pointer_two]
how_close = abs(target - sum_num)
if how_close < abs(target - result):
result = sum_num
pointer_one = pointer_one + 1
pointer_two = pointer_two - 1
print("Result: ", result)`
When you begin my advice is to use the print() to better understand your code:
iterate over items:
for i in nums:
print(i)
0 1 1 1
iterate over indexes:
for i in range(len(nums)):
print(i)
0 1 2 3
Regards
Your for loop iterates over the items of the list, but you use it as an index not the actual value.
The standard for loop with an index would in your case look as:
for i in range(len(nums)):
#rest of your code
Look at the docs for examples of both forms of for loops:
https://docs.python.org/3/tutorial/controlflow.html#for-statements

How to check elements in a list WITHOUT using for loops?

Apologies if the title of the question is phrased badly. I am currently trying to make a function that takes in a list of integers from 1 to n, where n is the length of the list. The function should return the first value that is repeated in the list. Duplicates are NOT always next to one another. If one or more integers is less than 1 or if it is not a list, the function should return -1. If there are no duplicates, return 0.
This is my current code:
def find_duplicates(ls):
if type(ls) != list:
return -1
non_dupe = []
i = 0
while i < len(ls):
if ls[i] < 1:
return -1
break
if ls.count(i) > 1:
return i
break
else:
non_dupe.append(i)
i += 1
if len(non_dupe) == len(ls):
return 0
While this code works for a majority of test cases, it doesn't seem to pass
print(find_duplicates([1, 2, 2, 0]))
as it returns 2 instead of the expected -1. I am relatively new to Python and I can't seem to be able to fix this error. I've tried searching for ways to counter this problem but I am not allowed to use for loops to check through a list. Any help is greatly appreciated.
EDIT: I am not allowed to use any of the following but anything else is accepted.
for loops
min() / max()
enumerate() / zip ()
sort()
negative indexing e.g ls[-1]
list slicing
Your code returns a duplicate prematurely; traversing the list, the function first finds 2 as a duplicate, return it, and halts the function immediately. But it has not seen the 0 at the end.
So, you need to let the function see the list all the way towards the end, looking for a negative number. If a negative number is found along the way, you can halt the function. If it does not see a negative number until the end, then let it return the duplicate value:
def find_duplicates(ls):
if not isinstance(ls, list): # check whether ls is a list
return -1
dup = 0
seen = [] # list of numbers seen so far
i = 0 # index
while i < len(ls):
if ls[i] < 1: # if a negative number is found, return -1
return -1
if ls[i] in seen and dup == 0:
dup = ls[i]
seen.append(ls[i])
i += 1
return dup
print(find_duplicates([1, 2, 2, 0])) # -1
print(find_duplicates([1, 1, 2, 2, 3])) # 1
Problem is beacause you are breaking while loop when find a duplicated. In that case, function is finding first the duplicated.
Try this:
def find_duplicates(ls):
if type(ls) is not list:
return -1
duplicated = 0
i = 0
while i < len(ls):
if ls[i] < 1:
return -1
if ls.count(ls[i]) > 1 and duplicated == 0
duplicated = ls[i]
i += 1
return duplicated
Your test case returns 2 because 2 stay at lower indexes comparing to 0.
I would suggest to sort the list before moving on:
def find_duplicates(ls):
if type(ls) != list:
return -1
sorted_list = ls.sorted() #Assign sorted `ls` to another variable, while keeping the order of `ls` intact
non_dupe = []
i = 0
while i < len(ls):
if ls[i] < 1:
return -1
break
if ls.count(i) > 1:
return i
break
else:
non_dupe.append(i)
i += 1
if len(non_dupe) == len(ls):
return 0
Another method I would recommend is using set - a built-in data type of Python. Maybe you should consider trying this approach later on when all test cases are passed. Have a look at this Tutorial for set usage: https://www.w3schools.com/python/python_sets.asp.
You were very close. Try this:
def find_duplicates(ls):
if type(ls) != list:
return -1
non_dupe = []
i = 0
while i < len(ls):
if ls[i] < 1:
return -1
elif ls[i] in non_dupe:
return ls[i]
else:
non_dupe.append(i)
i += 1
return 0
my_list = [1,2,2,0]
result = list(set(filter(lambda x: my_list.count(x) > 1 , my_list)))
# Result => [2]
I hope this solves your problem

Why is my break statement not working as it exceeds the condition?

add = lambda x,y : x+y
list1 = [1,2,3,4,5]
count = 0
for num1 in list1:
if count > len(list1):
break
else:
print(add(num1,list1[count+1]))
count += 1
In the code above, why is the for loop not breaking as it exceeds the condition?
In fact you do not need the break statement (nor lambda expression). You may write you code as:
list1 = [1,2,3,4,5]
for i in range(len(list1)-1):
print list1[i] + list1[i+1]
Even better to use zip here:
for a, b in zip(list1, list[1:]):
print a+b
The for loop executes once per element in list1, so count will never be bigger than the length of that list.
I've you want to stay with tihs code, change the if statement:
if count >= len(list1) - 1:
and it will break before running out of the bounds of the list in
print(add(num1,list1[count+1]))
The error is on this line:
print(add(num1,list1[count+1]))
When you use count + 1 you're falling into an index out of range.
To keep your logic, you should use count + 1 >= len(list1)
for num1 in list1:
if count + 1 >= len(list1):
break
else:
print(add(num1,list1[count + 1]))
count += 1

Counter through embedded if statements inside for loop

So, I have a script in python (2.7) that makes a list of 1000000 numbers between 1 and 5000 and then runs a for loop over the entire list checking each element against multiple embedded if statments.
ex:
i = 0
for number in random_list:
i += 1
if random_list[number] <= 3000:
i += 1
if random_list[number] <= 300:
i += 1
if random_list[number] <= 30:
i += 1
if random_list [number] <= 3:
i += 1
break
print i
the whole point being I want to see how many "checks" occur over the entire list.
unfortunately my i value is less than the total number of elements in the list which should not be the case since each element should be checked at least once. I'm getting something in the range of 1000's to 10000's.
I'm sure there's a more pythonic way of doing this, so any advice on how to achieve what I'm trying will be greatly appreciated.
extra = 0
values = (random_list[number] for i,number in enumerate(my_numbers))
for v in values:
extra += sum(v < x for x in [3000,300,30,3])
if v < 3:break;
print i+extra
maybe ...

Python - variable not updating in loop

I am trying to solve the 'Love-Letter' mystery problem of HackerRank using Python, but I am stuck at a place where in my loop a variable is not getting updated.
s = input()
first_char = s[0]
last_char = s[-1]
ascii_first_char = ord(first_char)
ascii_last_char = ord(last_char)
count = 0
i = 1
while ascii_first_char < ascii_last_char:
count += abs((ascii_last_char-ascii_first_char))
ascii_first_char = ord(s[i])
ascii_last_char = ord(s[-i])
i += 1
print(count)
If you try to run that, you would see that alc is not changing it's value according to ord(s[i]) where I keeps incrementing. Why is that happening?
You get the first letter with s[0] and the last with s[-1]. In your loop you take the next letters with the same index i.
I don't understand your condition in the while loop. Instead of "ascii_first_char < ascii_last_char" you should test if you have looked at every element of the string. For that we have to loop len(s)/2 times. Something like:
while i < len(s) - i:
or equivalent
while 2*i < len(s):
And this conditions only work for even length. I prefer for-loops when I know how many times I will loop
current_line = input()
# if length is even, we don't care about the letter in the middle
# abcde <-- just need to look for first and last 2 values
# 5 // 2 == 2
half_length = len(current_line) // 2
changes = 0
for i in range(index):
changes += abs(
ord(current_line[i]) - ord(current_line[-(i+1)])
)
print (changes)
s1 = ['abc','abcba','abcd','cba']
for s in s1:
count = 0
i = 0
j = -1
median = len(s)/2
if median == 1:
count += abs(ord(s[0])-ord(s[-1]))
else:
while i < len(s)/2:
count += abs(ord(s[j])-ord(s[i]))
i += 1
j -= 1
print(count)

Categories

Resources