1

The code I have can convert a string into an integer or a float depending on the string itself.

def convert_data(data: List[List[str]]) -> None:
   for sublist in data: #Accesses each element in data
      for index, element in enumerate(sublist): 
         if element.isnumeric(): #If element is a number, check to see if it can be an int
            sublist[index] = int(element) #Convert to an int
   
         elif element.replace('.', '').isnumeric(): #If element is a number, check to see if it can be a float
            sublist[index] = float(element) #convert to a float
         
         else:
            sublist[index] = sublist[index] #If it isn't a number, return the string as it is

our_data = [['no'], ['-123'], ['+5.6', '3.2'], ['3.0', '+4', '-5.0']]

convert_data(our_data)

After the function has run, our_data should be:

[['no'], [-123], [5.6, 3.2], [3, 4, -5]]

However, I get:

[['no'], ['-123'], ['+5.6', 3.2], [3.0, '+4', '-5.0']]

I need to make it so that it will convert anything with a '+' or '-' into an integer/float, instead of returning it as a string. How can I go about doing this?

I apologize if you think my code is messy, I'm just quickly trying to solve this issue I am having. Thank you for your help!

2 Answers2

1

Cause:

'+' and '-' are not is_numeric() - you need to handle those manually if you want to keep your approach.

See farther down for a shorter and better way to do the same thing.

Fix:

def convert_data(data: List[List[str]]) -> None:
   for sublist in data: #Accesses each element in data
      for index, element in enumerate(sublist):
         sign = 1 
         # parse sign for later multiplication
         if element.startswith("+"):
             element = element[1:]
         elif element.startswith("-"):
             sign = -1
             element = element[1:]

         if element.isnumeric():  #   '12345'
            sublist[index] = sign * int(element)  
   
         elif element.replace('.', '').isnumeric():  # '123.45' but also '12.3.2020'
            sublist[index] = sign * float(element)   # convert to a float
         
         else:
            sublist[index] = sublist[index]          # keep as is

our_data = [['no'], ['-123'], ['+5.6', '3.2'], ['3.0', '+4', '-5.0']]
convert_data(our_data)
print(our_data)  

Output:

[['no'], [-123], [5.6, 3.2], [3.0, 4, -5.0]]

Optimization and more pythonic:

def convert_data(data )  :
    for sublist in data: 
        for index, element in enumerate(sublist):
           try:
               element = float(element)
               if element.is_integer():
                   element = int(element)
           except ValueError:
               pass
           sublist[index] = element 

See "Ask forgiveness not permission" - explain

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • Minor nit. It's probably safe in this case because elements are modified in place, but you really shouldn't be modifying a list while you are iterating over the list. I'd be happier if the code started `for index in range(len(sublist)):` followed by `element = sublist[index]`. YMMV. – Frank Yellin Nov 12 '20 at 23:11
  • @Frank - what you refer to is shortening a list by removing elements from it. Modifying elements save to do - no reason to use indexing for that. Anf if you look carefully, the assignemt is done using index - gathered from enumerating the list. – Patrick Artner Nov 12 '20 at 23:12
  • Yes. No. Maybe. I believe you, but I can't really find any documentation that says one way or the other. If you knew of official Python documentation, I'd appreciate it. – Frank Yellin Nov 12 '20 at 23:16
  • @Frank logic: the problem with removing list elements is that you skip elements - you are on 3, next would be 4, but you remove 3 so 4 is now 3 and your next elment will be the new 4th (former 5th) hence errors because you skip handling some of the values. Definitively no problem if you just modify values. See f.e. https://stackoverflow.com/questions/44864393/modify-a-list-while-iterating – Patrick Artner Nov 12 '20 at 23:16
1

actually you don't need to handle with the string type neither with sings because float does it for you. You can just use try and except to try to convert the string into float, or to return the string when it is not possible:

def convert(x):
    try:
        return float(x)
    except:
        return x

our_data = [['no'], ['-123'], ['+5.6', '3.2'], ['3.0', '+4', '-5.0']]
new_data = []
for data in our_data:
    new_data.append(list(map(lambda x: convert(x), data)))

print(new_data)
Flavio Moraes
  • 1,331
  • 1
  • 5
  • 16