Tycho
Tycho

Reputation: 11

Issue regarding list iteration

I tried the following code to remove some special characters from string using loop

def chk(arr):
    i=0
    while i<len(arr):
        j=arr[i]
        if (ord(j)<65 or ord(j)>90) and (ord(j)<97 or ord(j)>122):
            if ord(j)==39:
                pass
            else:
                arr.remove(j)
        i+=1
st = "//wont won't"
arr=[]
arr[:0]=st
chk(arr)
print(arr)

I got the output as ['/', 'w', 'o', 'n', 't', 'w', 'o', 'n', "'", 't']

But I want ['w', 'o', 'n', 't', 'w', 'o', 'n', "'", 't']

The code does not consider one of the '/' while traversing. Why?

Upvotes: 0

Views: 56

Answers (2)

Samwise
Samwise

Reputation: 71574

Modifying a list as you're iterating over it usually produces weird results, and on top of that your ors and ands look a little suspicious with regards to how they handle characters in the middle of the range; it doesn't help that everything is obfuscated by using the character codes instead of the actual characters. I'm pretty sure you want something like:

>>> def chk(arr):
...     arr[:] = [c for c in arr if c.isalpha() or c == "'"]
... 
>>> st = "//wont won't"
>>> arr = list(st)
>>> chk(arr)
>>> print(arr)
['w', 'o', 'n', 't', 'w', 'o', 'n', "'", 't']

Upvotes: 0

Unmitigated
Unmitigated

Reputation: 89527

Your loop did not work properly because removing an element while iterating forward shifts all the next elements one index down, so you skip an element each time. Looping backwards or decrementing the index after removing will fix this.

# Decrementing index after removing:
def chk(arr):
    i=0
    while i<len(arr):
        j=arr[i]
        if (ord(j)<65 or ord(j)>90) and (ord(j)<97 or ord(j)>122):
            if ord(j)==39:
                pass
            else:
                arr.remove(j)
                i-=1
        i+=1

# Looping backwards:
def chk(arr):
    i=len(arr) - 1
    while i >= 0:
        j=arr[i]
        if (ord(j)<65 or ord(j)>90) and (ord(j)<97 or ord(j)>122):
            if ord(j)==39:
                pass
            else:
                arr.remove(j)
        i-=1

# Looping backwards with a for loop:
def chk(arr):
    for i in range(len(arr) - 1, -1, -1):
        j = arr[i]
        if (ord(j)<65 or ord(j)>90) and (ord(j)<97 or ord(j)>122):
            if ord(j)==39:
                pass
            else:
                arr.remove(j)

Upvotes: 1

Related Questions