How do I go back and forth in a loop? - python

So I have a sequence of items at these indexes 1 2 3 4 5 6 7 8 9 10. I need to add middle two elements at first:
output = i[5]+i[6]
and for every next iteration, output must be add with left element and then right element.
output = output + i[4]
next step,
output = output + i[7]
I don't know how do that in loop or any other structure. Could anyone recommend anything to me? I'm working with python, but I just need pseudocode.

To get an element from either left or either right for each iteration I'd use a while statement in combination with a pop() on the list.
Code:
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
total = 0
while len(l):
total += l.pop(len(l) // 2)
Output:
print(total)
55
The total progression is:
0 + 6 = 6
6 + 5 = 11
11 + 7 = 18
18 + 4 = 22
22 + 8 = 30
30 + 3 = 33
33 + 9 = 42
42 + 2 = 44
44 + 10 = 54
54 + 1 = 55

newlist=[1,2,3,4,5,6,7,8,9,10]
while(len(newlist)>0):
lengthi=(len(newlist)//2)-1
lengthj=(len(newlist)//2)
sum=(newlist[lengthi]+newlist[lengthj])
del newlist[lengthi:(lengthj)+1]
print(sum)
This works for the list I have tried it, however this will change according to the length of your list. This works for even, if the length changes the code gives errors because there will be a non matched element at the end. Also you can do this by not deleting the list by copying the variable into another variable and then deleting the variables from it is probably better.

The common item here is that the two subscripts have to add up to 11.
output = 0
for left in range(5, 0, -1):
right = 11 - left
output += i[left]
output += i[right]
I left the solution longer than necessary, since you seem to have other steps in between.

Well you can start from middle of the list and then as you go forward, add left and right elements together.
m = len(a)//2 # middle of the list
output = 0
for i in range(m):
output += a[m-i-1] + a[m+i]
I'm trusting here that length of the list is an even number. Although odd length won't be a problem, just that the last element of list will be ignored.

Related

algorithm merge sort because after dividing the list and sorting the first two values ​in my case 16 and 44 why is the function executed again?

I was studying the logic behind the merge sort algorithm in python. After dividing the list and ordering the first two values ​​in my case 16 and 44, why the function is executed again?
This is the code:
def MergeSort(list):
if len(list)>1:
mid = len(list)//2 #splits list in half
left = list[:mid]
right = list[mid:]
MergeSort(left) #repeats until length of each list is 1
MergeSort(right)
a = 0
b = 0
c = 0
while a < len(left) and b < len(right):
if left[a] < right[b]:
list[c]=left[a]
a = a + 1
else:
list[c]=right[b]
b = b + 1
c = c + 1
while a < len(left):
list[c]=left[a]
a = a + 1
c = c + 1
while b < len(right):
list[c]=right[b]
b = b + 1
c = c + 1
return list
According to my logic once I get to the end of the function since there is no cycle I should exit the function and yet (as it should be) the other two values ​​are also analyzed and sorted.
The code seems to be working fine. There is no need for return list since MergeSort is modifying the original list.
and yet (as it should be) the other two values ​​are also analyzed and sorted
The code seems to be working fine. There is no need for return list since MergeSort is modifying the original list.
and yet (as it should be) the other two values ??are also analyzed and sorted
The function MergeSort call itself twice:
MergeSort(left)
MergeSort(right)
The order will be depth first, left first. No merging takes place until there are only 2 elements to merge: 1 in left [44], 1 in right [16], which it merges to produce [16,44]. After that it returns to call MergeSort(right) for [83,7], which merges to produce [7,83]. It then returns back to the prior level of nesting to merge [16,44] with [7,83]. Showing the order of operations:
44 16 83 7
44 16
44
16
16 44
83 7
83
7
7 83
7 16 44 83

Default stepsize is already 1, so why does adding [::1] change my output?

I encountered something I don't understand. I created a simple example in order to explain it. I have the following list:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I iterate through the list, printing the value at the current index, and remove the value if it is even. This results in the next value getting skipped because they all move up one index (filling the gap created by the removal).
for i in numbers:
print(i)
if i % 2 == 0:
numbers.remove(i)
This results in the following output, which is as expected:
1
2
4
6
8
10
When iterating through the list backwards, this problem will be avoided, since all the lower indexes won't be affected by the removal of a higher index.
for i in numbers[::-1]:
print(i)
if i % 2 == 0:
numbers.remove(i)
Which results in (as expected):
10
9
8
7
6
5
4
3
2
1
Now we've arrived at the part I don't understand. As far as I know the default stepsize is 1, so adding [::1] shouldn't make any difference right? Well, it does...
for i in numbers[::1]:
print(i)
if i % 2 == 0:
numbers.remove(i)
Which results in:
1
2
3
4
5
6
7
8
9
10
As yous see all the numbers are getting printed, while I expected some to be skipped due to the shifting explained earlier.
Can someone explain why this is?
So, the answer is already there in the comments, just a proper explanation here:
Basically, when you say:
for i in numbers:
print(i)
if i % 2 == 0:
numbers.remove(i)
You are iterating through the list numbers
But when you write:
for i in numbers[::1]:
print(i)
if i % 2 == 0:
numbers.remove(i)
It can be seen as an equivalent to:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]# <-------------
num2 = numbers.copy() #or numbers[::1] <-------------- |
# i.e. python automatically creates a copy of the | |
# list numbers to iterate through | |
# since it seems like you are iterating through a | |
# slice of the original list | |
# | |
for i in numbers[::1]: # iterates through------------- |
print(i) # |
if i % 2 == 0: # |
numbers.remove(i) # this removes elements from --
The difference? The copy created is only stored until iteration is done. Hence even when the elements are removed, since the current list is the same, no number is skipped.

IndexError: list index out of range in Reversal of arrays

I am trying to reverse arrays in groups. I have wasted more than half an hour finding the problem but not able to figure out how is index is out of range.
Here is my code:
def rev(A,S,N):
start=S
end=N
while start<end:
A[start],A[end]=A[end],A[start] #error here
start+=1
end-=1
return A
def reverseInGroups(A,N,K):
#Your code here
rev(A,0,K)
rev(A,K,N) #error here
return A
Here is the error I am getting
Sample Input 1 : N=5 K=3 A= [1,2,3,4,5]
Sample Output 1 : 3 2 1 5 4
Sample Output 2 N= 8 K=3 A=[1,2,3,4,5,6,7,8]
Sample Output 2 : 3 2 1 6 5 4 8 7
For more information please visit this link
How about
def rev(a,start,end, middle):
assert 0 <= start <= middle <= end < len(a)
a[start:middle] = reversed(a[start:middle])
a[middle:end] = reversed(a[middle:end])
return a
There is no need to use / iterate positions at all - this avoids your error because slicing can handle oversized slices: [1,2,3,4][2:99] works w/o error.
def rev(data, start, end):
"""Reverses the range start:end (end exclusive) of the given list.
No safeguards whatsoever so only use with correct data. Out of bounds
is irrelevant due to slices used to reverse."""
data[start:end] = data[start:end][::-1] # you need end+1 if you want inclusive
return data
def reverseInGroups(A,N,K):
rev(A,0,K)
rev(A,K,N)
return A
l = list(range(11))
print ( reverseInGroups(l , 8, 3)) # why N (the bigger number) first?
to get
[2, 1, 0, 7, 6, 5, 4, 3, 8, 9, 10]
#0 1 2 3 4 5 6 7 8 9 10 # 0-3(exclusive) and 3-8(exclusive) reversed
To revere all K sized groups do
def reverseInGroups(A,K):
pos_at = 0
while pos_at < len(A):
rev(A, pos_at, pos_at+K)
pos_at += K
return A

Slicing large lists based on input

If I have multiple lists such that
hello = [1,3,5,7,9,11,13]
bye = [2,4,6,8,10,12,14]
and the user inputs 3
is there a way to get the output to go back 3 indexes in the list and start there to get:
9 10
11 12
13 14
with tabs \t between each space.
if the user would input 5
the expected output would be
5 6
7 8
9 10
11 12
13 14
I've tried
for i in range(user_input):
print(hello[-i-1], '\t', bye[-i-1])
Just use negative indexies that start from the end minus the user input (-user_input) and move to the the end (-1), something like:
for i in range(-user_input, 0):
print(hello[i], bye[i])
Another zip solution, but one-lined:
for h, b in zip(hello[-user_input:], bye[-user_input:]):
print(h, b, sep='\t')
Avoids converting the result of zip to a list, so the only temporaries are the slices of hello and bye. While iterating by index can avoid those temporaries, in practice it's almost always cleaner and faster to do the slice and iterate the values, as repeated indexing is both unpythonic and surprisingly slow in CPython.
Use negative indexing in the slice.
hello = [1,3,5,7,9,11,13]
print(hello[-3:])
print(hello[-3:-2])
output
[9, 11, 13]
[9]
You can zip the two lists and use itertools.islice to obtain the desired portion of the output:
from itertools import islice
print('\n'.join(map(' '.join, islice(zip(map(str, hello), map(str, bye)), len(hello) - int(input()), len(hello)))))
Given an input of 3, this outputs:
5 6
7 8
9 10
11 12
13 14
You can use zip to return a lists of tuple where the i-th element comes from the i-th iterable argument.
zip_ = list(zip(hello, bye))
for item in zip_[-user_input:]:
print(item[0], '\t' ,item[1])
then use negative index to get what you want.
If you want to analyze the data
I think using pandas.datafrme may be helpful.
INPUT_INDEX = int(input('index='))
df = pd.DataFrame([hello, bye])
df = df.iloc[:, len(df.columns)-INPUT_INDEX:]
for col in df.columns:
h_value, b_value = df[col].values
print(h_value, b_value)
console
index=3
9 10
11 12
13 14

for loop in Python, change the list it was looping

cleanedList = [x for x in range(0, 100, 1)]
idx = 0
for val in cleanedList:
check = abs(cleanedList[idx])
idx = idx + 1
if check % 5 == 0: ##### Conditions changed and change the list
cleanedList = a new list that loops over.
This is arbitrary example. I want to change the list it is looping now when the conditions fails. I tried this way. I don't think it actually changed the list it is looping now. Please correct me.
It is not advisable to change the list over which you are looping. However, if this is what you really want, then you could do it this way:
cleanedList = list(range(0, 100, 1))
for i, _ in enumerate(cleanedList):
check = abs(cleanedList[i])
if check % 5 == 0: ##### Change the list it is looping now
cleanedList[:] = range(60, 100, 2)
This is an interesting one, because you haven't actually mutated the list.
cleanedList = [x for x in range(0, 100, 1)] # Creates list1
idx = 0
for val in cleanedList: # begin iterating list1. It's stored internally here.
check = abs(cleanedList[idx])
print val, check,
idx = idx + 1
if check < 30: ##### Change the list it is looping now
cleanedList = [x for x in range(60,100,2)] # reassign here, but it becomes list2.
The output tells the story:
0 0 1 62 2 64 3 66 4 68 5 70 6 72 7 74 8 76 9 78 10 80 11 82 12 84 13 86 14 88 15 90 16 92 17 94 18 96 19 98
Because you didn't mutate, you reassigned, the dangling reference to the list you're iterating over initially still exists for the context of the for loop, and it continues way past the end of list 2, which is why you eventually throw IndexError - there are 100 items in your first list, and only 20 in your second list.
Very briefly, when you want to edit a list you're iterating over, you should use a copy of the list. so your code simply transfers to:
for val in cleanedList[:]:
and you can have all kinds of edits on your original cleanedList and no error will show up.

Categories

Resources