0

isdigit() doesn't work here:

li=["word",'2.134123']
for i in li:
 if i.isdigit():
  li.remove(i)
R S
  • 155
  • 9
  • You are modifying a list while iterating it, which will cause problems. Also, '.' is not a digit character. – nneonneo Nov 02 '15 at 20:48
  • `.isdigit()` is intended to be used for `int`, not `float`. Look at [this question](http://stackoverflow.com/questions/4138202/python-using-isdigit-for-floats) for a workaround. Moreover, you should not modify a mutable object like a list while iterating through it or wou will get unexpected results. – Delgan Nov 02 '15 at 20:49
  • isdigits does not work with float. See here http://stackoverflow.com/questions/4138202/python-using-isdigit-for-floats – UglyCode Nov 02 '15 at 20:51

3 Answers3

3

isdigit does not pass the check for floats represented as a string.

The help of isdigit specifies:

Return True if all characters in S are digits
    and there is at least one character in S, False otherwise.

So, with that, your work around will be to find some other way to determine whether something does in fact pass the "number" check.

What you can do is wrap an attempt to convert each item to a float in a try/except and then append to a new list for every item that falls in to the except:

def remove_numbers(li):
    numberless = []
    for i in li:
        try:
            float(i)
        except:
            numberless.append(i)
    return numberless

res = remove_numbers(["word",'2.134123'])
print(res)
# outputs ['word']

an alternative can be to modify the function to simply return True or False based on the float test, and make use of filter to "filter" the list based on the result of the remove_numbers method. (Thanks @Pynchia)

def not_a_float(s):
    try:
        float(s)
        return False
    except:
        return True

res = filter(not_a_float, ["word", '2.134123'])

In terms of performance, there is no real advantage between the two, probably because the gain in the implementation of filter is spent by the extra frame setup in the call to not_a_float

python3 -mtimeit -s'from remove_floats import remove_numbers_loop; from random import randint' -s'l=[str(i) if randint(0,100)< 20 else "abc"+str(i) for i in range(1000000)]' -s 'remove_numbers_loop(l)'
python3 -mtimeit -s'from remove_floats import remove_numbers_filter; from random import randint' -s'l=[str(i) if randint(0,100)< 20 else "abc"+str(i) for i in range(1000000)]' -s 'remove_numbers_filter(l)'

100000000 loops, best of 3: 0.00929 usec per loop
100000000 loops, best of 3: 0.0107 usec per loop
Pynchia
  • 10,996
  • 5
  • 34
  • 43
idjaw
  • 25,487
  • 7
  • 64
  • 83
  • upvoted. The code could go in a function, say `is_not_float`. It would return True/False only, no appending. Then simply use `filter(is_not_float, li)` (transformed to a list, if on py3) – Pynchia Nov 02 '15 at 21:08
  • ahem... given you are creating a new list, my point being `filter` is faster than appending in a for loop, me thinks. Read my comment again, if you will. The function should only check a value isn't/is a float. Just my thoughts, no compelling reason for changing the code – Pynchia Nov 02 '15 at 21:17
  • 1
    @Pynchia +1 you are fantastic. Cheers. – idjaw Nov 02 '15 at 21:23
  • I took the liberty to edit your code and remove an unnecessary `for` loop that was left behind – Pynchia Nov 02 '15 at 21:27
  • absolutely...I should have copied instead of editing. Was fine in my editor. – idjaw Nov 02 '15 at 21:27
  • for fun and learning, I have timed the two solutions. They are head-to-head, even for big lists. I guess the advantage of the `filter` implementation is negated by the extra frame setup in the call to `not_a_float`. So no real advantage, just a slightly different implementation. – Pynchia Nov 02 '15 at 21:57
  • 1
    That's interesting. Look at this too: http://stackoverflow.com/a/29508145/1832539 – idjaw Nov 02 '15 at 22:06
2

Isdigit doesnt work if the number have decimals. Return False in this case.

1

See https://docs.python.org/2/library/stdtypes.html

str.isdigit()

Return True if all characters in the string are digits and there is at least one character, False otherwise.

Your string contains also the decimal dot and that's why the function returns False.

dlask
  • 8,776
  • 1
  • 26
  • 30