Length of list within list (jagged list) becomes zero after leaving loop - python-3.x

All -
For a Selenium webscraper using Python 3.x - I am trying to get a printout that depends upon the length of each 1d index in a jagged list, in this case only 2d. The list is named masterViewsList, and the lists it contains are versions of a list named viewsList. Below see how my list masterViewsList of viewsList's is constructed:
from selenium import webdriver
import os
masterLinkArray = []
masterViewsList = []
# a bunch of code here that I cut out for simplicity's sake
for y in range(0, len(masterLinkArray)):
browser = webdriver.Chrome(chromePath)
viewsList = []
browser.get(masterLinkArray[y])
productViews = browser.find_elements_by_xpath("// *[ # id = 'lightSlider'] / li / img")
counter = - 1
for a in productViews:
counter = counter + 1
viewsList.append(a.get_attribute('src'))
print(viewsList[counter])
print(len(viewsList))
masterViewsList.append(viewsList)
if y == 10:
print(masterViewsList[y])
print(len(masterViewsList[y]))
del viewsList[:]
print(len(masterLinkArray))
print(len(masterViewsList))
print(len(masterViewsList[0]))
print(len(masterViewsList[1]))
print(len(masterViewsList[10]))
The printout is this:
["https://us.testcompany.com/images/is/image/lv/1/PP_VP_L/544_PM2_Front%20view.jpg?wid=140&hei=140","https://us.testcompany.com/images/is/image/lv/1/PP_VP_L/544_PM1_Side%20view.jpg?wid=140&hei=140","https://us.testcompany.com/images/is/image/lv/1/PP_VP_L/544_PM1_Interior%20view.jpg?wid=140&hei=140","https://us.testcompany.com/images/is/image/lv/1/PP_VP_L/544_PM1_Other%20view.jpg?wid=140&hei=140","https://us.testcompany.com/images/is/image/lv/1/PP_VP_L/544_PM1_Other%20view2.jpg?wid=140&hei=140"]
5
79
79
0
0
0
As you can see, neither the masterLinkArray, nor the masterViewsList are empty - they're 79 long. Also, print(masterViewsList[y]) prints out an actual non-empty list, one with a recognized length of 5. Oddly, once I leave the for y loop, len(masterViewsList[*any integer*]) prints out to "0". These similar questions:
Find the dimensions of a multidimensional Python array,
Find length of 2D array Python,
both indicate that len(array[*integer*]) is the proper way to get the length of a list within a list, but in my case this appears not to be working consistently.

The masterViewlist is empty a the point where you call the len method on it. That's why all the results of the len method will be zero.
In the first short version of your code this is not clear because the following line of code is missing in that version:
del viewsList[:]
After appending the viewList to masterViewList, this line of code causes the masterViewlist being empty again. This is because the del command deletes all references to this viewList including the one in the masterViewlist. You can remove this del of the viewList because you starts with a new viewList every time you are back in the beginning of the outer for loop.

Related

comparing int value in list throws index out of range Error

I'm struggling to grasp the problem here. I already tried everything but the issue persist.
Basically I have a list of random numbers and when I try to compare the vaalues inside loop it throws "IndexError: list index out of range"
I even tried with range(len(who) and len(who) . Same thing. When put 0 instead "currentskill" which is int variable it works. What I don't understand is why comparing both values throws this Error. It just doesn't make sence...
Am I not comparing a value but the index itself ???
EDIT: I even tried with print(i) / print(who[i] to see if everything is clean and where it stops, and I'm definitelly not going outside of index
who = [2, 0, 1]
currentskill = 1
for i in who:
if who[i] == currentskill: # IndexError: list index out of range
who.pop(i)
The problem is once you start popping out elements list size varies
For eg take a list of size 6
But you iterate over all indices up to len(l)-1 = 6-1 = 5 and the index 5 does not exist in the list after removing elements in a previous iteration.
solution for this problem,
l = [x for x in l if x]
Here x is a condition you want to implement on the element of the list which you are iterating.
As stated by #Hemesh
The problem is once you start popping out elements list size varies
Problem solved. I'm just popping the element outside the loop now and it works:
def deleteskill(who, currentskill):
temp = 0
for i in range(len(who)):
if who[i] == currentskill:
temp = i
who.pop(temp)
There are two problems in your code:
mixing up the values and indexes, as pointed out by another answer; and
modifying the list while iterating over it
The solution depends on whether you want to remove just one item, or potentially multiple.
For removing just one item:
for idx, i in enumerate(who)::
if i == currentskill:
who.pop(idx)
break
For removing multiple items:
to_remove = []
for idx, i in enumerate(who)::
if i == currentskill:
to_remove.append[idx]
for idx in reversed(to_remove):
who.pop(idx)
Depending on the situation, it may be easier to create a new list instead:
who = [i for i in who if i != currentskill]
Your logic is wrong. To get the index as well as the value, use the built-in function enumerate:
idx_to_remove = []
for idx, i in enumerate(who)::
if i == currentskill:
idx_to_remove.append[idx]
for idx in reversed(idx_to_remove):
who.pop(idx)
Edited after suggestion from #sabik

Sorting algoritm

I want to make my algorithm more efficient via deleting the items it already sorted, but i don't know how I can do it efficiently. The only way I found was to rewrite the whole list.
l = [] #Here you put your list
sl = [] # this is to store the list when it is sorted
a = 0 # variable to store which numbers he already looked for
while True: # loop
if len(sl) == len(l): #if their size is matching it will stop
print(sl) # print the sorted list
break
a = a + 1
if a in l: # check if it is in list
sl.append(a) # add to sorted list
#here i want it to be deleted from the list.
The variable a is a little awkward. It starts at 0 and increments 1 by 1 until it matches elements from the list l
Imagine if l = [1000000, 1200000, -34]. Then your algorithm will first run for 1000000 iterations without doing anything, just incrementing a from 0 to 1000000. Then it will append 1000000 to sl. Then it will run again 200000 iterations without doing anything, just incrementing a from 1000000 to 1200000.
And then it will keep incrementing a looking for the number -34, which is below zero...
I understand the idea behind your variable a is to select the elements from l in order, starting from the smallest element. There is a function that does that: it's called min(). Try using that function to select the smallest element from l, and append that element to sl. Then delete this element from l; otherwise, the next call to min() will select the same element again instead of selecting the next smallest element.
Note that min() has a disadvantage: it returns the value of the smallest element, but not its position in the list. So it's not completely obvious how to delete the element from l after you've found it with min(). An alternative is to write your own function that returns both the element, and its position. You can do that with one loop: in the following piece of code, i refers to a position in the list (0 is the position of the first element, 1 the position of the second, etc) and a refers to the value of that element. I left blanks and you have to figure out how to select the position and value of the smallest element in the list.
....
for i, a in enumerate(l):
if ...:
...
...
If you managed to do all this, congratulations! You have implemented "selection sort". It's a well-known sorting algorithm. It is one of the simplest. There exist many other sorting algorithms.

unable to delete all element satisfying condition in a python list using enumerate

i am trying to delete zero values from the list using the below code
for id,row in enumerate(list):
if row[0]=="0":
del list(id)
this works fine for input like
[0,1,3,0,9,10,0,3,0,6]
but doesn't work as expected for inputs like
[0,0,1,3,4,0,0,4,5,6,0,0].
output: [0,1,3,4,0,4,5,6,0]
I guess its because the element right after the deleted one gets the id of the deleted element and enumerate increments the id which leaves the element after the one which is deleted unchecked.
so what can be done to check all the elements ? is there a better way ?
I made a little change to your code:
mylist = [0,0,1,3,4,0,0,4,5,6,0,0]
for id,row in reversed(list(enumerate(mylist))):
if(row==0):
del mylist[id]
If you loop your list in the way you did (from start to end) and delete an element while doing it, you'll end up jumping indexes because python does not recognize that an element has been deleted from the list.
If you have an array with 10 elements inside and you delete the first (idx 0), in the next iteration you will be at index 1, but the array has been modified, so your idx 1 is the idx 2 of your array before the deletion, and the real idx 1 will be skipped.
So you just need to loop your array in reverse mode, and you won't miss indexes.
If you print the value of mylist, you'll get [1, 3, 4, 4, 5, 6].
This problem is documented on this python page under 8.3:
https://docs.python.org/3/reference/compound_stmts.html
They suggest doing it this way by using a slice. It works for me:
a = [-2,-4,3,4]
for x in a[:]:
if x < 0: a.remove(x)
print ('contents of a now: ')
print(*a)
enumerate returns an object called enumerate object and it is iterable not actually a list. second thing row is not a list it is not subscriptable.
for i,row in enumerate(l):
if row==0:
del(l[i])
you will not get result you want this way.
try this:
t=[] #a temporary list
for i in l:
if i!=0:
t.append(i)
t will contain sublist of l with non zero elements.
put the above inside a function and return the list t .

merging some entries in a python list based on length of items

I have a list of about 20-30 items [strings].
I'm able to print them out in my program just fine - but I'd like to save some space, and merge items that are shorter...
So basically, if I have 2 consecutive items that the combined lengths are less than 30, I want to join those to items as a single entry in the list - with a / between them
I'm not coming up with a simple way of doing this.
I don't care if I do it in the same list, or make a new list of items... it's all happening inside 1 function...
You need to loop through the list and keep joining items till they satisfy your requirement (size 30). Then add them to a new list when an element grows that big.
l=[] # your new list
buff=yourList[0] if len(yourList)>0 else "" # hold strings till they reach desired length
for i in range(1,len(yourList)):
# check if concatenating will exceed the size or not
t=yourList[i]
if (len(buff) + len(t) + 1) <= 30:
buff+="/"+t
else:
l.append(buff)
buff=t
l.append(buff) # since last element is yet to be inserted
You can extend method of list as follows:
a = [1,2,3]
b = [4,5,6]
a.append('/')
a.extend(b)
You just need to check the size of two list a and b as per your requirements.
I hope I understood your problem !
This code worked for me, you can check to see if that's what you wanted, it's a bit lenghty but it works.
list1 = yourListOfElements
for elem in list1:
try: # Needs try/except otherwise last iteration would throw an indexerror
listaAUX = [] # Auxiliar list to check length and join smaller elements. You can probably eliminate this using list slicing
listaAUX.append(elem)
listaAUX.append(list1[list1.index(elem)+1])
if len(listaAUX[0]) + len(listaAUX[1]) < 30:
concatenated = '/'.join(listaAUX)
print(concatenated)
else:
print(elem)
except IndexError:
print(elem)

Why does len(point_str) return 1?

import sys
string_input = "6\n212 132322\n212 21\n65 56\n32 3\n3232 32\n313 13\n0"
# a two dimensional array to store points
points = []
for line in string_input.split("\n"):
# split the inputed line using space to divide x and y coordinate
points_str = line.split(" ")
point_coordinate = []
if len(points_str) != 1:
for val in points_str:
point_coordinate.append(int(val))
points.append(point_coordinate)
print(str(points))
print(len(points_str))
Why does the len(points_str) return 1? I am also very confused why 1 != 1 continues to perform the rest of the code.
First your loop run through all iterations, then you print out len(points_str). Now points_str gets a new value in each iteration, but since you only print at the end, you get the length of the last value that points_str was assigned. This is the last element of string_input.split("\n"), which is '0'. The length of '0' is indeed 1.
Try moving the line
print(len(points_str))
inside of the loop (that is, just add four spaces) and check the output. You should also try to print out points_str, not just its length.
Well, because it's of length 1. At least in your first iteration.
Your first line is "6", so points_str is ["6"], which has a length of 1.
You should really use a debugger.

Resources