What is the correct loop range - python

I want to delete some array from list. But I'm using wrong range.
At start the range is correct.
This should work, if string in variable result[b][2:3] then delete result[b]
for b in range(len(result)):
if 'FillLevel' in result[b][2:3]:
del result[b]
After that I have error: IndexError: list index out of range
I want to find this string and delete whole line (array):
V;4;FillLevel[1];CPUA.DB1610.0,I0,64;RW
V;4;FillLevel[2];CPUA.DB1610.0,I;RW
V;4;FillLevel[5];CPUA.DB1610.6,I;RW
V;4;FillLevel[6];CPUA.DB1610.8,I;RW
V;4;FillLevel[11];CPUA.DB1610.18,I;RW
Why this code:
print(result[4][2:3])
print(result[5][2:3])
print(result[6][2:3])
print(result[7][2:3])
print(result[8][2:3])
print(result[9][2:3])
print(result[10][2:3])
b = 0
while b < len(result):
if 'FillLevel' in result[b][2:3]:
del result[b]
del adress[b]
print('yes')
b += 1
Showing only once 'yes' ?
['FillLevel']
['FillLevel[1]']
['FillLevel[2]']
['FillLevel[3]']
['FillLevel[4]']
['FillLevel[5]']
['FillLevel[6]']
yes

The issue is that del result[b] changes the composition (and the length of) result, thereby interfering with your loop.
Perhaps the easiest way to fix this is by rephrasing your code as a list comprehension:
result = [r for r in result if 'FillLevel' not in r[2:3]]
Alternatively, you could fix it by iterating in reverse:
for b in range(len(result) - 1, -1, -1):
if 'FillLevel' in result[b][2:3]:
del result[b]

Let's say there are 10 items in the list.
Half-way through you delete one of the items; now there are 9 items in the list.
In the last cycle, your loop asks for the tenth item. My guess is that's where the index error is happening (though it could be due to the [2:3] call as well, depending on the contents of your list)
A more pythonic solution would be
result = [val for val in result if 'FillLevel' not in val[2:3]]

If you want to preserve the same list and parse it in the strait order you can use a while loop which evaluate the len(result) in each iteration
b = 0
while b < len(result) :
if 'FillLevel' in result[b][2:3]:
del result[b]
b += 1

for first
- it's mach easyer to iterate by list withot getting length, probably you are got an error coz length of list is changing during loop
for second
- you are trying to check 'FillLevel' in slice of string. slice return one character
- try to not midify your list but make new one with filtered items
like this:
new_list = []
for b in result:
if 'FillLevel' not in b:
new_list.append(b)
or check about List Comprehensions and type this:
[i for i in result if 'FillLevel' not in i]

Related

How to handle operating on items in a list without perfectly even len()?

I'm trying to operate on every 5 items in a list, but can't figure out how to handle the remaining items if they don't divide evenly into 5. Right now I'm using modulo, but I can't shake the feeling it's not quite the right answer. Here's an example...
list = ["ValA","ValB","ValC","ValD","ValE","ValF","ValG","ValH","ValI","ValJ","ValK","ValL","ValM","ValN",]
newlist = []
i = 0
for o in list:
i += 1
newlist.append(o)
if i % 5 == 0:
for obj in newlist:
function_for(obj)
newlist.clear()
This code will execute function_for() twice, but not a third time to handle the remaining 4 values. If I add an 'else' statement it runs on every execution.
What's the correct way to handle a situation like this?
This way is pretty easy, if you don't mind modifying the list:
mylist = ["ValA","ValB","ValC","ValD","ValE","ValF","ValG","ValH","ValI","ValJ","ValK","ValL","ValM","ValN",]
while mylist:
function_for( mylist[:5] )
mylist = mylist[5:]
You can also check if the index is equal to the length of the list. (Additionally, it is more idiomatic to use enumerate instead of a counter variable here.)
lst = ["ValA","ValB","ValC","ValD","ValE","ValF","ValG","ValH","ValI","ValJ","ValK","ValL","ValM","ValN",]
newlist = []
for i, o in enumerate(lst, 1):
newlist.append(o)
if i % 5 == 0 or i == len(lst):
print(newlist)
newlist.clear()

Nested For Loop Copies the last line in set of indicies

for each in Dti:
i = 0
for each in Dti[0]:
xbi[t][i] = Dti[t][i]
print(t)
i = i + 1
t = t + 1
this is just a test that I'm doing to figure out why my complicated code isn't working. I'm trying to iterate through a list and then each value in the list to set a new list of lists equal to that value. I know I could just set them equal to each other, but it needs to be done this way for my more complicated program. Any tips? I'm getting Dti[-1] for each xbi[t]. I've tried with while too and got the same results
Try something like this:
for t, D in enumerate(Dti)
for i, d in enumerate(D):
xbi[t][i] = d
print(t)
You can use slicing in assignments to replace one list's elements with the elements of another list:
for t, row in enumerate(Dti):
xbi[t][:] = row

swapping elements in a for loop returns the same index after swap

can someone explain me the loop below:
for item in aList[start:end:1]:
aList[aList.index(item)],aList[aList.index(item)+1] = aList[aList.index(item)],aList[aList.index(item)+1]
Let s say aList = [5,2,3,6,1]. the first iteration the index would 0. in the second would be again 0 and after will be increased to 2. Thus it will choose [5,2] and will continue with [2,5] [3,6]....
Why is that and what is the right way to do this?
UPDATE: The above is just an example of a specific behavior I wanted to understand. the actual code tries to implement a coctail sort algorithm.
The actual code is like that
if f == 1:
for d in area[start:end:f]:
print area,f ,d,area[area.index(d)+1],area.index(d)+1
if d > area[area.index(d)+1]:
tmp = area.index(d)
area[tmp], area[tmp+1] = area[tmp+1],area[tmp]
area=area
end -= 1
f = ~f + 1
if f == -1:
for d in area[end:start:f]:
print area,f,d,area[area.index(d)-1],area.index(d)-1
if d < area[area.index(d)-1]:
tmp = area.index(d)
area[tmp], area[tmp-1] = area[tmp-1], area[tmp]
area=area
start += 1
f = ~f + 1
As John said, it is a bad idea to mutate a list whilst looping over it. Instead create a copy of the list and change the data in the copy of the list. However it's also unclear what you are trying to achieve so if you specify that there might be a better way to do it.
Before diving into the problem, it's worth noting there are a couple issues with the code as written.
start and end aren't defined
The assignment in the for-loop doesn't actually swap the order
Those things aside, the algorithm fails, because you iterate over every item. I'll go through 2 iterations to show you why that's so.
Let's use your example:
aList = [5,2,3,6,1]
First iteration:
item = 5
aList.index(5) = 0
so, we're going to swap aList[0] and aList[1]
at the end of the iteration, aList = [2,5,3,6,1]
Second iteration:
item = 2
Wait, why 2? Because the slice operation creates a new list that we're iterating over, and that list has the original order.
aList.index(2) = 0
so, we're going to swap aList[0] and aList[1]... again.
at the end of the iteration, aList = [5,2,3,6,1]... which is the original order.
And so on
On the third iteration, we'll wind up swapping the 3rd and 4th items. And on the fourth iteration of the loop, we'll swap them again.
You can verify this is the case by adding a print statement to your for-loop: print aList.
So how do you fix it?
You can get around this behavior by iterating over every other item, instead of every item. Try changing the slice stride (step) to 2, instead of 1.

How to skip empty lists when iterating over lists within a list?

Take the following code as an example:
a = [['James Dean'],['Marlon Brando'],[],[],['Frank Sinatra']]
n = 0
for i in a:
print a[n][0]
n = n + 1
I seem to be getting an error with the index value:
IndexError: list index out of range
How do I skip over the empty lists within the list named a?
Simple:
for i in a:
if i:
print i[0]
This answer works because when you convert a list (like i) to a boolean in an if statement like I've done here, it evaluates whether the list is not empty, which is what you want.
You can check if the list is empty or not, empty lists have False value in boolean context -
for i in a:
if i:
print a[n][0]
n = n + 1
Also, instead of using n separately, you can use the enumerate function , which returns the current element as well as the index -
for n, i in enumerate(a):
if i:
print a[n][0] # though you could just do - print i[0]
You could either make a test, or catch the exception.
# Test
for i in a:
if a[n]:
print a[n][0]
n = n + 1
# Exception
for i in a:
try:
print a[n][0]
except IndexError:
pass
finally:
n = n + 1
You could even use the condensed print "\n".join(e[0] for e in a if e) but it's quite less readable.
Btw I'd suggest using using for i, element in enumerate(a) rather than incrementing manually n
Reading your code, I assume you try to get the first element of the inner list for every non empty entry in the list, and print that. I like this syntax:
a = [['James Dean'],['Marlon Brando'],[],[],['Frank Sinatra']]
# this filter is lazy, so even if your list is very big, it will only process it as needed (printed in this case)
non_empty_a = (x[0] for x in a if x)
for actor in non_empty_a : print (actor)
As mentioned by other answers, this works because an empty list is converted to False in an if-expression

python - is this a valid for in loop?

I want to access the object, i.e. array[i], as well as the interator count, i.
This is what I'm trying:
for i, pinName in allPorts[startIndex:endIndex]:
#do stuff
I get errors further down, just wondering if it's this part of the code.
New to python here. Cheers.
I guess you rather are looking for:
for i, pinName in enumerate(allPorts[startIndex:endIndex]):
...
the enumerate() builtin takes any list (tuple, iterable, ...) and yields tuples of (index, item) with index starting at 0.
Consider enumerate() which returns a tuple with the index value and element:
startIndex = 2
endIndex = 4
for i, pinName in enumerate(allPorts[startIndex:endIndex], startIndex):
print('index = {} element = {}'.format(i, pinName))
yields:
index = 2 element = 66
index = 3 element = 99
Note the starting index value specified as 2nd parameter in enumerate() otherwise it will always start with index 0 (ignoring your startIndex, unless you always want to start with 0).
I suspect this is what you're thinking of:
for i, pinName in enumerate(allPorts[startIndex:endIndex]):
#do stuff
However, I don't think this will do what you expect. allPorts[startIndex:endIndex] will "slice" the list and create a new one, so allPorts[i] will still give the wrong index if startIndex != 0
If you need i to be the index in the original allPorts, then offhand I think this is what you'll have to do:
i = startIndex
while i < endIndex:
pinName = allPorts[i]
#do stuff
i += 1
As suggested in the comments, here's a much better way to do it:
for i in xrange(startIndex, endIndex):
pinName = allPorts[i]
#do stuff

Categories