IndexError: " pop index out of range" with a for loop
<p>Goodmorning,
I just wrote this program in python and this <code>IndexError</code> keeps showing up. I don't know how to resolve it, I even tried by using a while loop but nothing changed...I hope someone can help me with this problem!</p>

<p>Here is my code, it should check the length of the object of two lists (la, lb) and: remove the string from the la list  if the string is less long than the lb string and vice versa..plus it has to remove both of the strings if their length is the same.</p>

<pre><code>def change(l1,l2):
    la1 = l1[:]
    la2 = l2[:]
    i = 0
    for i in range(len(la1)): 
        if la1[i] == la2[i]:
            l1.pop(i)
            l2.pop(i)
        elif la1[i] &gt; la2[i]:
            l2.pop(i)
        elif la2[i] &gt; la1[i]:
            l1.pop(i)
</code></pre>

<p><strong>Assuming your lists are of equal lengths</strong></p>

<p>As has been pointed out in the comments, the <code>IndexError</code> happens due to your lists' length changing when you <code>pop()</code> an item. </p>

<p>Since you're iterating over your list using a <code>range(len(l))</code> in a <code>for</code> loop, which isn't updated after every completed loop, you'll eventually hit an index that's out of range. </p>

<p>An example, which you can try easily enough yourself:</p>

<pre><code>l = [1,2,3,4,5,6,7,8,9,10]

for i in range(len(l)):
    l.pop(i)
    print("Length of list", len(l))
</code></pre>

<p>Do not confuse yourself by calling <code>print(range(len(l))</code> in the for loop - this will give you an updated range, but is misleading. The <code>range</code> in the for loop is only called once, hence never updates while iterating.</p>

<p><strong>A different approach</strong></p>

<p>Instead of working with indices, try using <code>zip()</code> and building new lists, instead of changing existing ones.</p>

<pre><code>def change(l1, l2):
    new_l1 = []
    new_l2 = []
    for a, b in zip(l1, l2):
        if len(a) == len(b):
            continue # do nothing
        elif len(a)&lt;len(b):
            new_l2.append(b)
        elif len(a)&gt;len(b):
            new_l1.append(a)
    return new_l1, new_l2
</code></pre>

<p>This approach, essentially, generates the same list you create using <code>pop()</code>, while avoiding usage of indices. </p>

<p>Note that <code>zip()</code> will stop once it reaches the end of the smaller of both iterables. If your lists may not be of equal length, and you'd like to iterate until the longest of both iterables is iterated over entirely, use <code>zip_longest()</code>. But I do not think this is what you need in this case.</p>

<p><strong>Additional Notes</strong></p>

<p>You would also run into a problem if you were to iterate over your <code>list</code> using the following code:</p>

<pre><code>l = [i for i in range(10)]
for item in l:
    l.remove(item)
&gt;&gt;&gt;[1, 3, 5, 7, 9]
</code></pre>

<p>Essentially, it's <strong><em>not advisable to iterate over any <code>iterable</code> while changing it</em></strong>. This can result in anything from an <code>Exception</code> being thrown, to silent unexpected behaviour.</p>

<p>I'm aware you were avoiding this by looping over the copies, I just wanted to add this for posterity. </p>

python