0

I got a little question: I got 2 lists with equal lengths.

As you can see below in my code, if appropriate circumstances take place, I delete some of the elements from the list. I have to do my work very carefully so my question is - does the for loop check by every iteration if len(whole_st_gen) is changing ?? Won't it skip some items??

whole_st_gen = []
whole_end_gen = [] // the length of both of them is 38273
if_merge = 0
here_merge = 0
deleting = False

for x in range (0, len(whole_st_gen)):
    if_merge = x
    if x == len(whole_st_gen)-1:
        break
    for y in range (x+1, len(whole_st_gen)):
        if whole_end_gen[x]>whole_end_gen[y]:
            deleting = True
            here_merge = y
            continue
        else:
            break
    if deleting == True:
        deleting = False
        del whole_st_gen[x:here_merge]
        del whole_end_gen[x:here_merge]
    if_merge = 0
    here_merge = 0

print len(whole_st_gen) # here's length is 1852, so i think it could work properly, just want to be sure!
sys.exit()
martynasma
  • 8,542
  • 2
  • 28
  • 45
theCember
  • 71
  • 1
  • 7
  • 1
    Just use a while loop: `i = 0`; `while i < len(my_list): ...`; if an element was deleted, then don't increment `i`, otherwise do increment `i`. – Kijewski Aug 11 '15 at 10:06
  • Your code needs some cleaning up. Give me a minute.. – Cyphase Aug 11 '15 at 10:08
  • 1
    No, a for loop wont recognise that the list has been modified. Check out the answer here: [strange result when removing item from a list](http://stackoverflow.com/questions/6260089/strange-result-when-removing-item-from-a-list) – SuperBiasedMan Aug 11 '15 at 10:10
  • @SuperBiasedMan, related for sure, but there's also the implied question of, "How do I make _this_ work?". – Cyphase Aug 11 '15 at 10:11
  • Thanks! Okay mabye I'll use while, but i want to check @Cyphase solution :) – theCember Aug 11 '15 at 10:12
  • 1
    @theCember, what is the code supposed to be doing? Do you know whether your current code works? – Cyphase Aug 11 '15 at 10:13
  • @theCember, I don't understand; what is your code supposed to do? – Cyphase Aug 11 '15 at 10:26
  • @Cyphase Look i have lists _st_gen , end_gen they are the ranges , at for example: whole_st_gen [10] #here for example 600 whole_end_gen[10] #here 700 , this pair make range next is _st+_end at [11] It gives me the distance where i need to put some values in other stuff in this range, the problem is, at position for example [9] st==550 and end==100 So I delete position 10 because, range pair at [9] covers this at [10] Clear enough? – theCember Aug 11 '15 at 10:27
  • You delete pair 10 because it's covered by pair 9? But it's not; and in fact, pair 9 is starting at a higher number than it ends at. Please try to elaborate. – Cyphase Aug 11 '15 at 10:29
  • Here are the real last 4 pairs from my project (i zipped two of the lists, sort them by _st , ascending) _ST _END a)248872850 248919146 b)248873855 248873960 c)248874248 248874319 d)248931413 248937105 As you see a) have the least _st and this range covers b,c,d, thats why I delete b,c,d cause this range is only need to. So I think my way of solving this is right :) – theCember Aug 11 '15 at 10:41
  • It doesn't cover `d`, just so you know. So you want to delete all ranges that are completely included in another range, right? – Cyphase Aug 11 '15 at 10:55
  • Yes exactly want to delete ranges which are in other bigger ranges :) – theCember Aug 11 '15 at 11:54
  • @theCember, what about, e.g. `(1, 5)`, `(6, 10)`, `(10, 15)`, `(13, 17)`? Mention me so I'll see it. – Cyphase Aug 11 '15 at 13:14

3 Answers3

1

No , when you are using range() method, it does not check the length of the array in each iteration. Especially in Python 2.x , range() returns a list , which is what you iterate over, and this list is created at the start of the loop , it does not get recalculated in each iteration. So there can be multiple issues you can run into when using above method.

One being that you can skip some elements, since if you delete an element from the list, the indices of the list are rearranged to make a contigous sequence, so you would end up missing some elements.

Secondly, you can end up getitng IndexError , Simple example of that -

>>> l = [1,2,3,4]
>>> for i in range(0,len(l)):
...     del l[i]
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
IndexError: list assignment index out of range

This is because like I said in starting range() computes the complete range (even xrange() in Python 2.x) at the start itself. This does not happen for you because of -

if x == len(whole_st_gen)-1:
    break

Like said in the comments an easier way for you to go would be to use while loop , which does not increment when deleting the item. Example -

if_merge = 0
here_merge = 0
deleting = False
x = 0
while x < len(whole_st_gen):
    for y in range (x+1, len(whole_st_gen)):
        if whole_end_gen[x]>whole_end_gen[y]:
            deleting = True
            here_merge = y
        else:
            break
    if deleting == True:
        deleting = False
        del whole_st_gen[x:here_merge]
        del whole_end_gen[x:here_merge]
    else:
        x += 1
    here_merge = 0

print len(whole_st_gen)
sys.exit()
Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
0

In the for statement the expression list (after the in) is evaluated first to get an iterator (or iterable) which is then used for the iteration, the expression list is not evaluated again in each iteration.

In your case you call the range function to retrieve an iterator (in python3) or iterable (in python2 in the form of a list). In both cases the iterator/iterable will yield len(whole_st_gen) (as it evaluates when you reach the for statement from above) numbers (ranging from zero). If you alter the whole_st_len in the loop it will not affect the iterator and it will yield the same numbers anyway (leading to you skipping numbers, and eventually get numbers that are beyond the indices for whole_st_gen).

As opposed to the situation where you iterate over the container itself the behaviour when you do this is fully specified. You may delete and insert elements in the container if you are careful.

skyking
  • 13,817
  • 1
  • 35
  • 57
-1

Here is a straight answer to your question, you should not delete items on a list while iterating on the same list, it yields unexpected results to you as some items will be skipped. Inorder to avoid this you can use copy of same list in the iteration.

Suresh Kota
  • 305
  • 1
  • 6
  • 19
  • 3
    While your point is true, this makes more sense as a comment than an answer. – SuperBiasedMan Aug 11 '15 at 10:13
  • This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient [reputation](http://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](http://stackoverflow.com/help/privileges/comment). – bitoiu Aug 11 '15 at 16:17
  • @bitoiu, Have you read the question?, I am sure this answers his question It may require some more explanation though – Suresh Kota Aug 12 '15 at 09:04
  • @pydev, I guess the 3 upvotes to the first comment confirm my comment. – bitoiu Aug 12 '15 at 19:31
  • @bitoiu, the first comment does not say " This does not provide an answer to the question". It says " this makes more sense as a comment than an answer " – Suresh Kota Aug 13 '15 at 07:11