0

I have a list that looks like this

lst = ['a','b','43.23','c','9','22']

I would like to remove the elements that cannot be represented as floats and hence I am doing the following (Attempt 1):

for i,j in enumerate(lst):
    try:
        lst[i]=float(j)
    except:
        lst.remove(j)

Which leaves the list looking like this

lst = ['b', 43.23, '9', 22.0]

whereas what I need is this

lst = [43.23, 9.0 , 22.0]

And so I'm doing the following:

for i,j in enumerate(lst):
    try:
        lst[i]=float(j)
    except:
        pass
lst = [i for i in lst if type(i) != str]

Is there a cleaner way to do this.?

EDIT: Changed the name of example list from 'list' to 'lst' based on the recommendations below.

Ash Sharma
  • 470
  • 3
  • 18

5 Answers5

2

You can use the following function from this stackoverflow post:

def isfloat(value):
  try:
    float(value)
    return True
  except ValueError:
    return False

And, then use it in a list comprehension:

>>> l = ['a','b','43.23','c','9','22']
>>> [float(x) for x in l if isfloat(x)]
# [43.23, 9.0, 22.0]
Community
  • 1
  • 1
AKS
  • 18,983
  • 3
  • 43
  • 54
  • Roughly the same as what I am doing. Would like to know what am I doing wrong in the first attempt.? – Ash Sharma Apr 13 '16 at 09:15
  • In the first attempt, you are removing the items from list while changing the `ith` value in the list and that's why there is discrepancy. – AKS Apr 13 '16 at 09:21
  • Yes, the tuple values in the next() iterator for enumerate() gets the updated 'j' values whereas the index 'i' remains same and reads the 'j' from the updated list. Any ideas what can be done to make it work.? – Ash Sharma Apr 13 '16 at 09:23
  • I wouldn't chose to go over playing with the index in the list when I have a better method which is cleaner. – AKS Apr 13 '16 at 09:26
1

First you shouldn't name your variable list it will shadow the built-in list function/class. You can use a simple function to do this:

>>> lst = ['a','b','43.23','c','9','22']
>>> def is_float(el):
...     try:
...         return float(el)
...     except ValueError:
...         pass
... 
>>> [i for i in lst if is_float(i)]
['43.23', '9', '22']
>>> [float(i) for i in lst if is_float(i)] # to return a list of floating point number
[43.23, 9.0, 22.0]

The problem with your code is that you are trying to modify your list while iterating. Instead you can make a copy of your list then use the element index to remove their value.

lst = ['a','b','43.23','c','9','22']
lst_copy = lst.copy()
for el in lst:
    try:
        float(val)
    except ValueError:
        lst_copy.remove(el)

Of course this is less efficient than the solution using the list comprehension with a predicate because you first need to make a copy of your original list.

styvane
  • 59,869
  • 19
  • 150
  • 156
  • Roughly the same as what I am doing (i haven't used a function of course). Would like to know what am I doing wrong in the first attempt.? – Ash Sharma Apr 13 '16 at 09:16
  • @AshutoshSharma I've updated my answer. I hope it makes sense now. – styvane Apr 13 '16 at 09:34
0

You shouldn't manipulate the list you're iterating through (and you shouldn't call it list neither, since you would shadow the built-in list), since that messes up with the indexes.

The reason why 'b' shows up in your output is that during the first iteration, 'a' is not a float, so it gets removed. Thus your list becomes:

['b','43.23','c','9','22']

and b becomes list[0]. However, the next iteration calls list[1] skipping thus 'b'.

To avoid such an issue, you can define a second list and append the suitable values to that:

l1 = ['a','b','43.23','c','9','22']
l2 = []

for item in l1:
    try:
        l2.append(float(item))
    except ValueError:  # bare exception statements are bad practice too!
        pass
Railslide
  • 5,344
  • 2
  • 27
  • 34
  • Got that, but I have a dictionary full of many lists like the one above and creating another dictionary full of lists..may not look good..? I am okay with manipulating the original lists though. – Ash Sharma Apr 13 '16 at 09:19
  • Updated the answer so that it explains why you shouldn't manipulate the list while looping through that @AshutoshSharma For the dictionary, you could just assign `l2` to the old key – Railslide Apr 13 '16 at 09:28
0

Would be better in considering iterators to efficiently use system memory. Here is my take to the solution.

def func(x):
    try:
        return float(x)
   except ValueError:
        pass

filter(lambda x: x, map(func, li))
Anvesh
  • 607
  • 1
  • 5
  • 19
0

Borrowing idea from this post : python: restarting a loop, the first attempt can be fixed with a simple while loop

lst = ['a','b','43.23','c','9','22']
temp = 0
while temp<len(lst):
      try:
         lst[temp] = float(lst[temp])
         temp+=1
      except ValueError:
         lst.remove(lst[temp])
         temp = 0

which leaves me with the desired result (by resetting the loop iterator)

lst = [43.23, 9.0 , 22.0]
Community
  • 1
  • 1
Ash Sharma
  • 470
  • 3
  • 18