While loop gets ignored - python

Hej Everyone,
The idea of the script is to grab image links from a catalogue page of my company's website and change them to image links with a higher resolution and filter for image format, where the variable to filter for is found in the link itself, in this case the capital P. Afterwards a csv is generated with the links.
The transformation, filtering and writing to csv works fine, but my problem is that I don't want all the 80 products, I only want 8 to be in the list nl.
The links list contains elements like this one https://rndr.mywebsite.com/media/catalog/product/seo-cache/x386/19/95/19-95-101P/How-Hard-You-Hit-Butcher-Billy-Premium-Poster.jpg
NOTE: variables ratio and creatives (inputnumber-1) are defined by commandline input. Just assume that the input was ratio = P and creatives = 9-1.
NOTE2: For quicker testing, the links list has a limit of 15 elements by now.
nl= []
string1= "https://rndr.mywebsite.com/media/catalog/product/cache/x800/"
string2= ".jpg"
while len(nl) <= creatives:
for index in range(len(links)):
if "P" in "".join(links[index].split("/", 12)[10]) and "P" in ratio:
print("YEAH", len(nl))
nl.extend([string1 + "/".join(links[index].split("/", 11)[8:11]) + string2])
else:
print ("Ups", len(nl))
print (nl)
The actual output is
('YEAH', 0)
('YEAH', 1)
('YEAH', 2)
('YEAH', 3)
('Ups', 4)
('YEAH', 4)
('YEAH', 5)
('Ups', 6)
('YEAH', 6)
('YEAH', 7)
('YEAH', 8)
('YEAH', 9)
('YEAH', 10)
('YEAH', 11)
('YEAH', 12)
[https://rndr.mywebsite.com/media/catalog/product/cache/x800/19/95/19-95-101P.jpg, transformed-link2,...,transformed-link12]
As you can see the filtering and transforming works fine, but it should stop after having 9 links in the list nl.

As mentioned by Coldspeed, in the inner loop you're adding a whole batch of items to nl, thus overshooting the limit. To fix it, you could get rid of the while loop and do this instead:
for index in range(len(links)):
if "P" in "".join(links[index].split("/", 12)[10]) and "P" in ratio:
print("YEAH", len(nl))
nl.append(string1 + "/".join(links[index].split("/", 11)[8:11]) + string2)
if len(nl) > creatives:
break
else:
print ("Ups", len(nl))

Adding a couple of print statements like this can help you figure out exactly what is going on:
while len(nl) <= creatives:
print('outer loop')
for index in range(len(links)):
print('inner loop')
...
You've got a nested loop here. What happens is, inside the inner loop, the condition for the outer loop is not checked, until the inner loop has finished iterating. What you'd need to do is put an explicit break inside the inner loop.
Look at this answer for a solution. :)

You're doing a for loop inside the while loop. The while loop will only check its condition upon finishing the first for loop, by which point you've already looped over every element in links.
E.g.
i = 0
while i < 10:
for z in range(20):
i = z
print(i)
will print all the way to 19, because the precondition for the while loop will only be checked when the inner for loop finishes.

Related

Python Find the mean school assignment - What is a loop?

I have been working on this assignment for about 2 weeks and have nothing done. I am a starter at coding and my teacher is really not helping me with it. She redirects me to her videos that I have to learn from every time and will not directly tell or help me on how I can do it. Here are the instructions to the assignment (said in a video, but made it into text.
Find the mean
Create a program that finds the mean of a list of numbers.
Iterate through it, and instead of printing each item, you want to add them together.
Create a new variable inside of that, that takes the grand total when you add things together,
And then you have to divide it by the length of your array, for python/java script you’ll need to use the method that lets you know the length of your list.
Bonus point for kids who can find the median, to do that you need to sort your list and then you need to remove items from the right and the left until you only have one left
All you’re doing is you need to create a variable that is your list
Create another variable that is a empty one at the moment and be a number
Iterate through your list and add each of the numbers to the variable you created
Then divide the number by the number of items that you had in the list.
Here's what I've done so far.
num = [1, 2, 3, 4, 5, 6];
total = 0;
total = (num[0] + total)
total = (num[1] + total)
total = (num[2] + total)
total = (num[3] + total)
total = (num[4] + total)
total = (num[5] + total)
print(total)
However, she tells me I need to shorten down the total = (num[_] + total) parts into a loop. Here is how she is telling me to do a loop in one of her videos.
for x in ____: print(x)
or
for x in range(len(___)): print (x+1, ____[x])
there is also
while i < len(___):
print(___[i])
i = i + 1
I really don't understand how to do this so explain it like I'm a total noob.
First of all, loops in python are of two types.
while: a while loop executes the code in a body until a condition is true. For example:
i = 0
while(i < 5):
i = i + 1
executes i = i + 1 until i < 5 is true, meaning that when i will be equal to 5 the loop will terminate because its condition becomes false.
for: a for loop in python iterates over the items of any sequence, from the first to the last, and execute its body at each iteration.
Note: in both cases, by loop body I mean the indented code, in the example above the body is i = i + 5.
Iterating over a list. You can iterate over a list:
Using an index
As each position of the array is indexed with a positive number from 0 to the length of the array minus 1, you can access the positions of the array with an incremental index. So, for example:
i = 0
while i < len(arr):
print(arr[i])
i = i + 1
will access arr[0] in the first iteration, arr[1] in the second iteration and so on, up to arr[len(arr)-1] in the last iteration. Then, when i is further incremented, i = len(arr) and so the condition in the while loop (i < arr[i]) becomes false. So the loop is broken.
Using an iterator
I won't go in the details of how an iterator works under the surface since it may be too much to absorb for a beginner. However, what matters to you is the following. In Python you can use an iterator to write the condition of a for loop, as your teacher showed you in the example:
for x in arr:
print(x)
An iterator is intuitively an object that iterates over something that has the characteristic of being "iterable". Lists are not the only iterable elements in python, however they are probably the most important to know. Using an iterator on a list allows you to access in order all the elements of the list. The value of the element of the list is stored in the variable x at each iteration. Therefore:
iter 1: x = arr[0]
iter 2: x = arr[1]
...
iter len(arr)-1: x = arr[len(arr)-1]
Once all the elements of the list are accessed, the loop terminates.
Note: in python, the function range(n) creates an "iterable" from 0 to n-1, so the for loop
for i in range(len(arr)):
print(arr[i])
uses an iterator to create the sequence of values stored in i and then i is in turn used on the array arr to access its elements positionally.
Summing the elements. If you understand what I explained to you, it should be straightforward to write a loop to sum all the elements of a list. You initialize a variable sum=0 before the loop. Then, you add the element accessed as we saw above at each iteration to the variable sum. It will be something like:
sum = 0
for x in arr:
sum = sum + x
I will let you write an equivalent code with the other two methods I showed you and do the other points of the assignment by yourself. I am sure that once you'll understand how it works you'll be fine. I hope to have answered your question.
She wants you to loop through the list.
Python is really nice makes this easier than other languages.
I have an example below that is close to what you need but I do not want to do your homework for you.
listName = [4,8,4,7,84]
for currentListValue in listName:
#Do your calculating here...
#Example: tempVar = tempVar + (currentListValue * 2)
as mentioned in the comments w3schools is a good reference for python.

How do I implement 2 python range functions at the same time?

I have a statement which is working fine.
for i in range(1, 4):
piece = driver.find_element_by_xpath('//*[#id="js_proList"]/ul[1]/li[{}]/div/div[2]/p'.format(i))
piece.click()
time.sleep(2)
driver.back()
After it gets finished with this loop I want to run it again but with /ul[2]. and then /ul[3] and so on...
...//[#id="js_proList"]/ul[2]/...
...//[#id="js_proList"]/ul[3]/...
I can't get the coding for two ranges in the same sentence.
Thanks
You can use a nested for loop.
x = 10 # How many times do you want to loop over /ul[INDEX]
# Outer loop
for j in range(1, x):
# Inner loop
for i in range(1, 4):
piece = driver.find_element_by_xpath('//*[#id="js_proList"]/ul[{}]/li[{}]/div/div[2]/p'.format(j, i))
piece.click()
time.sleep(2)
driver.back()
nested loops of implementation is accurate , you can also try updating xpath dynamically once one iteration is done.

IndexError: list index out of range - sometimes it runs and some times it is not

i have a situation that i am not sure how to solve.
sometimes when i run the program it's running perfectly and sometimes it says
list index out of range
the code:
hashtag_list = ['urban', 'hipster', 'retro']
for hashtag in hashtag_list:
tag = randint(1,3)
driver.get('https://www.instagram.com/explore/tags/' + hashtag_list[tag] + '/')
sleep(5)
any suggestions? - it's not the whole code tho but i figured it's all i need. - please let me know if any other information is needed
Python list are zeroed indexed. That means the first index of a list starts from 0. So the indexes for hastag_list are 0, 1, 2. However, randint(1,3) is inclusive, so tag will sometimes randomly be assigned 3.
It should start to become clear what the problem is. Since the maximum index of hashtag_list is 2, and tag is sometimes 3, then sometimes you will be indexing hashtag_list out of range.
The simple solution would be to use randint(0, 2) rather than randint(1, 3). However, a cleaner solution would be to use random.choice to choose a random option from hashtag_list:
from random import choice
# ...
hashtag_list = ['urban', 'hipster', 'retro']
for hashtag in hashtag_list:
tag = choice()
driver.get('https://www.instagram.com/explore/tags/' + hashtag_list[tag] + '/')
sleep(5)
randint(a, b) produces a random integer in the range [a, b] inclusive, those sometimes when it doesn't work it's producing 3, and 3 is beyond the list. Change it to randint(0, 2), because in Python (and many other languages), a list with n elements' indices start from 0 and end at n - 1. Thus:
# elements: ['urban', 'hipster', 'retro']
# indices: 0 1 2
Change
tag = randint(1,3)
to
tag = randint(0,2)

Only looping through even numbers

I am new to programming so forgive me if this is basic.
Below is part of my code for extracting Home and Away odds from many different bookmakers for a basketball match.
If I just loop through every element in the range, I am left with home and away odds all in one column, however, I want a separate column for home and away odds.
num_page_items = len(odds)
for i in range(num_page_items):
Home = (odds[2*i].text)
Away = (odds[2*i-1].text)
print(Home,Away)
My desired outcome is to display the home team odds next to the away team odds separated by a comma.
My code achieves this, however I believe it is not a great way of doing it as it technically runs into an error at the end (even though all of the data I'm after still displays).
How can I clean this up?
Thanks
You can create an iterable with a generator expression to extract the text attribute from the odd objects, and then pair them by zipping the iterable with itself, so that you can iterate through it to unpack Home and Away:
i = (odd.text for odd in odds)
for Home, Away in zip(i, i):
print(Home, Away)
num_page_items = len(odds)
for i in range(0, num_page_items, 2):
Home = odds[i].text # Starts from 0, goes till num_page_items, incrementing by 2 (even indices)
for i in range(1, num_page_items, 2):
Away = odds[i].text # Starts from 1, goes till num_page_items, incrementing by 2 (odd indices)
You run into an IndexError, since you access an element at index 2*i, where i iterates over values from 0 to the size of the list. For eg, if size is 10, you will end up trying to access odds[2*i] for i = 5, 6, 7... , the index of which is out of bounds
Another way to go is to do a check inside the for-loop whether i is odd or even. Just a work around of Shobhit Verma's answer.
num_page_items = len(odds)
for i in range(num_page_items):
if i % 2 == 0: #This is a sanity check to see if i is odd or even
Home = odds[i].text
else:
Away = odds[i].text
The itemgetter in the standard module operator is designed to select list contents. Fast, suitable for regular selection.
from operator import itemgetter
odds=[1,2,3,4,5,6]
num_page_items = len(odds)
getHome = itemgetter(*range(0,num_page_items,2))
getAway = itemgetter(*range(1,num_page_items,2))
Home = getHome(odds)
Away = getAway(odds)
print(Home)
print(Away)
Output:
(1, 3, 5)
(2, 4, 6)

Is loop "for" prior to "if" statement in Python?

I'm new to a programming language and wanted to start with Python as its the recommendation of most people (as far as i see).
So, im practising on some functions to improve my understanding on loops, and basic statements etc. Though i'm not very good at it yet, i do believe that i'll improve sooner or later.
Here is an example where i'm stuck at:
def L():
List = []
TauS = []
a = 12
for i in range(1,a+1):
if a % i == 0:
List.append(i)
if a % len(List) == 0:
TauS.append(a)
print(List)
print(TauS)
L()
This is the function i want to have and the output is:
[1, 2, 3, 4, 6, 12]
[12]
As i expected.However, the problem is that i want "a" to be a variable instead of a constant.Something like:
def L():
List = []
TauS = []
for a in range(2,20):
for i in range(1,a+1):
if a % i == 0:
List.append(i)
if a % len(List) == 0:
TauS.append(a)
print(List)
print(TauS)
L()
Fails because it seems like for loop is working before the 2nd if statement (if a % len(list)) == 0: TauS.append(a)).I have also tried a "while" loop instead of a "for" loop as:
a = 2
while a <= 20:
for i in range(1,a+1):...(The rest is the same)
It would be a better idea if your help focus on the basic ideas instead of just giving the right function.
Thanks a lot from now!
Regards.
Python uses indention levels to tell whether code is in within a function, loop or condition, the general thing being that if there is a : then all the code indented underneath it is within that statement.
The problem with your code is that the second if statement is on the same indention level as the for loop rather than being on the indention level below the for loop. This means that rather than running in the for loop it runs after it.
So to fix your code all you need to do is select the if statement and press crtl + ] which is pythons keyboard shortcut for indent code section.
edit:
I think what you're asking for is to get all the factors of numbers from 2 to 19 and then print numbers where the number of factors is a factor of that number.
def L():
List = []
TauS = []
for a in range(2,20):
l=[] #this is the list for each individual number
#if i is a factor of a add it to l
for i in range(1,a+1):
if a % i == 0:
l.append(i)
#if length of l is a factor of a add a to TauS
if a % len(l) == 0:
TauS.append(a)
List.append(l)
print(List)
print(TauS)
L()
It fails because of variable scope.
Python uses indention to represent code block. So, here for loop and 2nd if condition has same indention which means they belong to same code block and can access variables defined in the same or the outer code block. "List" & "Taus" in this case.
However, Variable "a" is localize to outer for loop and can be access in the same or inner for loop and cant be access from outside. Similarly variable "i" is specific to inner for loop and cant be access outside of the loops block, not even from outer for loop.
Hope it helps...

Categories