Reputation: 1
so I have a function which takes a list of lists and changes the type of each value depending on what the value represents:
def change_list(x):
"""
Convert every str in x to an int if it represents a
integer, a float if it represents a decimal number, a bool if it is
True/False, and None if it is either 'null' or an empty str
>>> x = [['xy3'], ['-456'], ['True', '4.5']]
>>> change_list(x)
>>> x
[['xy3' , -456], [True], [4.5]]
"""
for ch in x:
for c in ch:
if c.isdigit() == True:
c = int(c)
I've only posted part of the code, I feel as though once I can get that sorted I can apply a similar method in other if/elif/else to be able to get it all straight. My problem is when I apply this sort of method and then call x again the list is still returned as strings instead of ints or floats or bools.
ie if I called x after executing this function I would get:
x = [['xy3'], ['-456'], ['True', '4.5']]
instead of what is in the example code in the function. I'm not sure what's going wrong, any advice would be helpful.
Upvotes: 0
Views: 535
Reputation: 12669
Because when you do :
for ch in x:
for c in ch:
if c.isdigit() == True:
c = int(c) #yes it changed the type but it doesn't stroed in list
Yes you are changing the type but where are you storing changed stuff ??
For that, you have to tell the list to change at that index and for that, you can use enumerate :
item[index]=int(item1)
Second thing you are using isdigit() on float which will not work :
str.isdigit() will only return true if all characters in the string are digits. . and - are punctuation, not a digit.
So you can use try these two methods :
First Method :
x = [['xy3'], ['-456'], ['True', '4.5']]
for item in x:
if isinstance(item,list):
for index,item1 in enumerate(item):
if item1.replace("-","").isdigit():
item[index]=int(item1)
elif item1.replace(".","").isdigit():
item[index]=float(item1)
print(x)
output:
[['xy3'], [-456], ['True', 4.5]]
or if you want you can convert all int to float :
x = [['xy3'], ['-456'], ['True', '4.5']]
for item in x:
if isinstance(item,list):
for index,item1 in enumerate(item):
if item1.replace("-","").replace(".","").isdigit():
item[index]=float(item1)
print(x)
Second Method:
You can define your own isdigit()
function :
x = [['xy3'], ['-456'], ['True', '4.5']]
def isdigit(x):
try:
float(x)
return True
except ValueError:
pass
Then one line solution :
print([[float(item1) if '.' in item1 else int(item1)] if isdigit(item1) else item1 for item in x if isinstance(item,list) for index,item1 in enumerate(item)])
Detailed Solution:
for item in x:
if isinstance(item,list):
for index,item1 in enumerate(item):
if isdigit(item1)==True:
if '.' in item1:
item[index]=float(item1)
else:
item[index]=int(item1)
print(x)
output:
[['xy3'], [-456], ['True', 4.5]]
Upvotes: 1
Reputation: 1497
First: isdigit return false for negative value, that's whay you are not getting the integer in X
>>> x[1][0].isdigit()
False
Second:
You are not replacing the updating the variable x
in c = int(c)
x = [['xy3'], ['-456'], ['True', '4.5']]
for index, value in enumerate(x):
for i,v in enumerate(value):
try:
x[index][i] = eval(v)
except:
pass
Upvotes: 0
Reputation: 53525
isdigit
and isnumeric
will not work since '-456' contains -
and '4.5' contains '.'
Instead do:
x = [['xy3'], ['-456'], ['True', '4.5'], ['3']]
for ch in x:
for i in range(len(ch)):
try:
ch[i] = float(ch[i])
if int(ch[i]) == ch[i]:
ch[i] = int(ch[i])
except:
if ch[i] in ['True', 'False']:
ch[i] = (['True', 'False'][0] == ch[i])
print(x)
OUTPUT
[['xy3'], [-456], [True, 4.5]]
Upvotes: 0
Reputation: 178
Currently you are using the value of of the list, but not updating it. You therefore need to enumerate it, and change the list element directly by referencing to it.
The correct code would look something like this:
for idx,ch in enumerate(x):
for idx2,c in enumerate(ch):
if c.isdigit() == True:
x[idx][idx2] = int(c)
Upvotes: 0
Reputation: 59232
You're not updating the list. You're just assigning the value another value, which does, umm..nothing. Use an enumerate
function and the index value it provides and then change the value using the index.
for ch in x:
for c in ch:
if c.isdigit() == True:
c = int(c) # You're doing 'xyz' = int('xyz') which does nothing
Better still, since you're wanting to generate a new list based on the current list, it would be better to go for a map
inp_list = [...] # Your list
out_list = list(map(lambda nums: int(n) for n in nums if n.isDigit(), inp_list))
# The above is for only integer conversion but you get the idea.
Upvotes: 0
Reputation: 15071
you need to change the list element itself, not the local reference c
or ch
:
for i,ch in enumerate(x):
if ch ... # whatever logic
x[i] = ... # whatever value
Upvotes: 0