Can anyone help me understand how this for loop is running? - python

I am pretty familiar with the enumerate and 'range(len(iterable)' way of looping through a for loop. However, for whatever reason I can't seem to understand why the for loop is producing the following output.
lst = [-2, 0, 4, 5, 1, 2]
for num, b in enumerate(lst):
print(lst[b])
Output :
1
-2
1
2
0
4
I understand if I were to print(lst[num]) it would print the items of the list.
If I were to print(i) I would also print the items of the list.
If I print(num) I would print the indices.
I just can't figure out where the output is getting the numbers from.

For the enumerate function, b refers to the elements. But since the elements are also valid indices for the loop, they return a value.
SO:
lst = [-2, 0, 4, 5, 1, 2]
for num, b in enumerate(lst):
print(lst[b])
In this Every iteration is:
1) b = -2 => print(lst[b]) => lst[-2] => 1
2) b = 0 => print(lst[b]) => lst[0] => -2
3) b = 4 => print(lst[b]) => lst[4] => 1
4) b = 5 => print(lst[b]) => lst[5] => 2
5) b = 1 => print(lst[b]) => lst[1] => 0
6) b = 2 => print(lst[b]) => lst[2] => 4
Hence this is valid

lst = [-2, 0, 4, 5, 1, 2]
for index, value in enumerate(lst):
print(value)
# Prints each value
for index, value in enumerate(lst):
print(index)
# Prints each index
for index, value in enumerate(lst):
print(lst[index])
# Prints each value (but not really benefiting from enumerate)
for index, value in enumerate(lst):
print(lst[value])
# Meaningless
# Only works since value itself is an int
# Prints some element in lst whose index equals to value

If you're confused about why a piece of code is doing what it doing, it's frequently helpful to have it print out exactly what it's doing. In this case, printing out the values of b:
>>> lst = [-2, 0, 4, 5, 1, 2]
>>> for b in lst:
... print(f"lst[{b}] = {lst[b]}")
...
lst[-2] = 1
lst[0] = -2
lst[4] = 1
lst[5] = 2
lst[1] = 0
lst[2] = 4
As you can see, the b values go through the lst elements in order, and the lst[b] values that get printed on the right (which are the only values you printed originally) do indeed correspond to what you get by indexing lst.
Note that lists are zero-indexed, so lst[0] is the first element (-2), and a negative index counts that many spaces from the end, so lst[-2] is the second element from the end (1, the same as lst[4]).

Related

How to loop over a list and roll over at the end?

I have a list and I must move elements from it to another list, for example, I have this:
lst_one = [1, 2, 3, 4]
iterable = 6
lst_two = []
The result needed is this:
lst_one = []
lst_two = [2, 1, 4, 3]
In this case, the iterable is the steps I move through the list to find the next available number. When I find it, I have to add it to the new list and remove it from the old one. So, if 1 is the first number, I have to run though all the list and if the list is too short, continue counting again from the beginning over and over again, until the number is found and this should continue until there are no elements left in lst_one.
No functions or classes allowed!
I literally cannot start, because the "loop" stops at the end of the list and doesn't continue again from the beginning
lst = input()
num = int(input())
lst = lst.split(" ")
lst = [eval(i) for i in soldiers_list]
new_list = []
for i in range(num - 1, len(lst), num):
new_list.append(lst[i])
del lst[i]
Is this what you need?
lst_one = [1, 2, 3, 4]
iterable = 6
lst_two = []
i = 0
while len(lst_one) != 0:
i = (i+iterable-1) % len(lst_one)
lst_two.append(lst_one[i])
del lst_one[i]
This was an interesting question, OP!
Let's see the process in detail:
First we keep in mind that we need to deal with all the elements present in lst_one.
We can do that by storing the length of lst_one before doing anything else, and setting up a for loop with it:
lst_one = [1, 2, 3, 4]
iterable = 6
lst_one_len = len(lst_one)
for counter in range(lst_one_len):
Let's run through getting the output fpr two elements:
First element, iteration 1: 1, index 0
First element, iteration 2: 2, index 1
First element, iteration 3: 3, index 2
First element, iteration 4: 4, index 3
First element, iteration 5: 1, index 0 (roll over)
First element, iteration 6: 2, index 1
So, we're left with 2. Now, upon deleting 2 from the list, we're left with [1, 3, 4], and we were at index 1, so we continue from there.
Second element, iteration 1: 3, index 1
Second element, iteration 2: 4, index 2
Second element, iteration 3: 1, index 0 (roll over)
Second element, iteration 4: 3, index 1
Second element, iteration 5: 4, index 2
Second element, iteration 6: 1, index 0 (roll over)
So, we're left with 1. Now, upon deleting 1 from the list, we're left with [3, 4], and we were at index 0, so we continue from there.
And so on...
So, we need to keep track of the index we're at.
We can do that by setting up a variable previous_index and setting it to 0 before the for loop:
lst_one = [1, 2, 3, 4]
iterable = 6
lst_one_len = len(lst_one)
previous_index = 0
for counter in range(lst_one_len):
Now, imagine that the index in the previous step (just index, not previous_index), kept growing on beyond 4. This would obviously produce an IndexError, so we need to make sure that it doesn't.
But this also means that we can grow the index beyond 4 and then "collapse" it to the length of our list later.
So, we'll define it as an element index that goes previous_index elements beyond iterable, but we'all also have to subtract 1 to account for the fact that your question assumes indexing starts at 1, not 0:
lst_one = [1, 2, 3, 4]
iterable = 6
lst_two = []
lst_one_len = len(lst_one)
previous_index = 0
for counter in range(lst_one_len):
index = iterable + previous_index - 1
Now, we need to make sure that index doesn't go beyond the length of the list, and that's a simple matter of using the modulo operator %:
lst_one = [1, 2, 3, 4]
iterable = 6
lst_two = []
lst_one_len = len(lst_one)
previous_index = 0
for counter in range(lst_one_len):
index = iterable + previous_index - 1
collapsed_index = index % len(lst_one)
Now, we need to add the element at collapsed_index to lst_two and remove it from lst_one:
lst_one = [1, 2, 3, 4]
iterable = 6
lst_two = []
lst_one_len = len(lst_one)
previous_index = 0
for counter in range(lst_one_len):
index = iterable + previous_index - 1
collapsed_index = index % len(lst_one)
lst_two.append(lst_one[collapsed_index])
del lst_one[collapsed_index]
And finally, we need to set previous_index to collapsed_index so that we can continue from there. Also print the lists to see the result:
lst_one = [1, 2, 3, 4]
iterable = 6
lst_two = []
lst_one_len = len(lst_one)
previous_index = 0
for counter in range(lst_one_len):
index = iterable + previous_index - 1
collapsed_index = index % len(lst_one)
lst_two.append(lst_one[collapsed_index])
del lst_one[collapsed_index]
previous_index = collapsed_index
print(lst_two)

How to return the turn of an element in a list?

I want to know if an element is in the list multiple times and if so what is the order of the 2nd one. The 2nd one is important, not the 3rd or the 4th one.
list = [1, 3, 4, 2, 0, 1, 6, 7, 0]
My expected output is:
"1" is in list 2 times and the order of the 2nd "1" is six.
Doing it with one pass over the list, while saving the indexes of the target number and checking their amount in the end:
l = [1, 3, 4, 2, 0, 1, 6, 7, 0]
target = 1
idxs = []
for i, num in enumerate(l):
if num == target:
idxs.append(i)
if len(idxs) > 1:
print(f'"{target}" is in the list {len(idxs)} times and the order of the 2nd "{target}" is {idxs[1]+1}')
else:
print(f'{target} is in the list 0 or 1 times')
The indexes can also be obtained with a neat list-comprehension:
idxs = [i for i, num in enumerate(l) if num == target]
Pretty rough code, just to convey the logic you can apply to get it done:
list = [1, 3, 4, 2, 0, 1, 6, 1, 7, 0]
flagged = []
for index, elem in enumerate(list):
elem_count = list[index:].count(elem)
if elem_count > 1 and elem not in flagged:
flagged.append(elem)
temp_index = list[index + 1:].index(elem)
actual_index = index + temp_index + 1
print(str(elem) + ' is in the list ' + str(elem_count) + ' times and the order of 2nd is ' + str(actual_index))
# OP
# 1 is in the list 3 times and the order of 2nd is 5
# 0 is in the list 2 times and the order of 2nd is 9
Are you sure it's 6 and not 5? Indexing starts from 0.
In any case, you can use index for finding it:
first_idx = list.index(element)
print(list.index(element, first_idx + 1))
Like that you will find the first occurrence of the element and than return the index of the second one. If you want it 6 and not 5 - increment it by 1.

How does recursion access nested lists?

def count_even(obj):
"""
Return the number of even numbers in obj or sublists of obj
if obj is a list. Otherwise, if obj is a number, return 1
if it is an even number and 0 if it is an odd number.
#param int|list obj: object to count even numbers from
#rtype: int
>>> count_even(3)
0
>>> count_even(16)
1
>>> count_even([1, 2, [3, 4], 5])
2
"""
count = 0
if isinstance(obj, int):
if obj % 2 == 0:
return 1
else:
return 0
else:
for i in obj:
count += count_even(i)
return new
I don't understand how in the 2nd-last line "count+= count_even(i)", "recursion" is able to access, for example, the nested list [3,4] from [1,2,[3,4],5].
Wouldn't the for loop go through each item { i=0 (1), i=1 (2), i=2 ([3,4]), i=3 (5) }, looking for an int, and not have the if statement trigger for [3,4], since it's a list?
The function is able to access the nested list [3, 4] because, as you stated, the value [3, 4] skips over the first if (because [3, 4] is not an int) and so then executes the else. In the else, you will get another loop over [3, 4] which will then check 3 and 4 for odd/evenness.
here’s a trace to help you sort things out:
obj = [ 1, 2, [3, 4], 5 ]
count_even(obj) =>
count_even([ 1, 2, [3, 4], 5]) =>
is obj an `int`? No =>
for i in [ 1, 2, [3, 4], 5] =>
count_even(1) =>
is 1 an int? Yes => return 0 because 1 is odd
count_even(2)
is 2 an int? Yes => return 1 because 2 is even
count_even([3, 4]) =>
is [3, 4] an int? No =>
for i in [3, 4] =>
count_even(3) =>
Is 3 an int? Yes => return 0 because 3 is odd
count_even(4) =>
Is 4 and int? Yes => return 1 because 4 is even
count_even(5) =>
is 5 an int? Yes => return 0 because 5 is odd

creating sum of odd indexes python

I'm trying to create a function equal to the sum of every other digit in a list. For example, if the list is [0,1,2,3,4,5], the function should equal 5+3+1. How could I do this? My knowledge of Python does not extend much farther than while and for loops. Thanks.
Here is a simple one-liner:
In [37]: L
Out[37]: [0, 1, 2, 3, 4, 5]
In [38]: sum(L[1::2])
Out[38]: 9
In the above code, L[1::2] says "get ever second element in L, starting at index 1"
Here is a way to do all the heavy lifting yourself:
L = [0, 1, 2, 3, 4, 5]
total = 0
for i in range(len(L)):
if i%2: # if this is an odd index
total += L[i]
Here's another way, using enumerate:
L = [0, 1, 2, 3, 4, 5]
total = 0
for i,num in enumerate(L):
if i%2:
total += num
>>> arr = [0,1,2,3,4,5]
>>> sum([x for idx, x in enumerate(arr) if idx%2 != 0])
9
This is just a list comprehension that only includes elements in arr that have an odd index.
To illustrate in a traditional for loop:
>>> my_sum = 0
>>> for idx, x in enumerate(arr):
... if idx % 2 != 0:
... my_sum += x
... print("%d was odd, so %d was added. Current sum is %d" % (idx, x, my_sum))
... else:
... print("%d was even, so %d was not added. Current sum is %d" % (idx, x, my_sum))
...
0 was even, so 0 was not added. Current sum is 0
1 was odd, so 1 was added. Current sum is 1
2 was even, so 2 was not added. Current sum is 1
3 was odd, so 3 was added. Current sum is 4
4 was even, so 4 was not added. Current sum is 4
5 was odd, so 5 was added. Current sum is 9
let's take this list as an example:
l = [1,2,3,4,5]
for even indexes sum:
even_index_eles = l[1::2] # [2, 4]
sum(even_index_eles) # 6
for odd indexes sum:
odd_index_eles = l[::2] # [1, 3, 5]
sum(odd_index_eles) # 9
it's worked with odd or even length of list

Complex list and len computation

The following code has a output of [1, 3, 6, 10]. I understand how to get 1 and 3 but not 6 and 10.
In 1st loop, the first list item 1 is equal to[my_list[0]], 3 equals to [out_list[len(out_list)-1] + my_list[i]]
In 2nd loop, out_list = 4 + [1 + 3] = 8which is not 6...
def mystery(my_list):
out_list = [my_list[0]]
for i in range(1, len(my_list)):
out_list += [out_list[len(out_list)-1] + my_list[i]]
print(out_list)
mystery([1, 2, 3, 4]) #output[1, 3, 6, 10]
I'm very close to understand it, just need a bit more explanation. Am I right? 1st loop, out_list = 1, [out_list[len(out_list)-1] = 1, my_list[i]] = 2, therefore, [1, 3]. 2nd loop, out_list stays the same, then I'm stuck here...
output = mystery([1, 2, 3, 4]) # [1, 3, 6, 10]
output == [1, 1+2, 1+2+3, 1+2+3+4]
my_list initially is : [1, 2, 3, 4]
out_list initially is : [1]
out_list in 1 iteration outlist on each iter : [1]
here i is : 1
len(out_list) : 1 my_list[i]: 2
add next element using this statement : out_list += [out_list[len(out_list)-1] + my_list[i]]
check here : out_list[0] gives 1 add this to 2
out_list in 2 iteration outlist on each iter : [1, 3]
here i is : 2
len(out_list) : 2 my_list[i]: 3
add next element using this statement : out_list += [out_list[len(out_list)-1] + my_list[i]]
check here : out_list[1] gives 3 add this to 3
out_list in 3 iteration outlist on each iter : [1, 3, 6]
here i is : 3
len(out_list) : 3 my_list[i]: 4
add next element using this statement : out_list += [out_list[len(out_list)-1] + my_list[i]]
check here : out_list[2] gives 6 add this to 4
Finally output is : [1, 3, 6, 10]
out_list += [out_list[len(out_list)-1] + my_list[i]] this statement it appends previous element into out_list i.e why out_list += is used instead out_list = so only in 3rd and 4th iteration the result is 6 and 10
out_list[len(out_list)-1] is simply the last item in out_list, same as out_list[-1].
Adding items to the list is done obscurely. Doing lst += [smtn] is the same as doing lst.append(smtn)
Would this make the function more readable to you?
def mystery(my_list):
out_list = [my_list[0]]
for i in range(1, len(my_list)):
out_list.append(out_list[-1] + my_list[i])
print(out_list)
This code returns a list whose i's item is the sum of the first i items of the input. In the i iteration you take the sum of i-1 items (which is stored in i-1), and add the i-th item from the list. 3=1+2, 6=(1+2)+3, 10=(1+2+3)+4. Had the next item in my_list be 5, the next item in out_list would be 10+5 = 15.
Edit:
To clarify more, let's do it by stages.
my_list = [1,2,3,4] and we enter the method
upon entry, we have out_list = [my_list[0]]. so now out_list = [1].
Now we go into the loop:
First iteration, i=1. out_list[len(out_list)-1] + my_list[i] = out_list[0] + my_list[1] = 1 + 2 = 3. out_list = [1,3]
Second iteration, i=2. out_list[len(out_list)-1] + my_list[i] = out_list[1] + my_list[2] = 3 + 3 = 6. out_list = [1,3,6]
Third iteration, i=3. out_list[len(out_list)-1] + my_list[i] = out_list[2] + my_list[3] = 6 + 4 = 10. out_list = [1,3,6,10]
A pythonic way to do this really easily:
def summer_foo(my_list):
return [sum(my_list[:i+1]) for i in range(len(my_list))]
Brief explanation
Loop from 0 to the len of the list - len(my_list)
Sum all the elements which goes from 0 to i
Put this element in the list (this is done with the comprehension)
if iis equal to 0 you will get the first element.
if iis equal to 1 you will get the sum of the first and the second element (i belongs to [0,2))
And so on...

Categories