6

In Python, I want to convert a list of strings:

l = ['sam','1','dad','21']

and convert the integers to integer types like this:

t = ['sam',1,'dad',21]

I tried:

t = [map(int, x) for x in l]

but is showing an error.

How could I convert all intable strings in a list to int, leaving other elements as strings?

My list might be multi-dimensional. A method which works for a generic list would be preferable:

l=[['aa','2'],['bb','3']]

3
  • 1
    Note that [map(int, x) for x in l] will try to turn each string into a list of integers, character by character. You probably meant either map(int, l) or [int(x) for x in l]. Commented Mar 26, 2012 at 9:31
  • [int(x) for x in l] will throw ValueErrors for non-numeric strings. Commented Mar 26, 2012 at 9:53
  • 1
    map(lambda line: [int(i) if i.isdigit() else i for i in line.split(",")]) - note this does not account for negative integers. Commented Sep 8, 2017 at 18:48

6 Answers 6

12

I'd use a custom function:

def try_int(x):
    try:
        return int(x)
    except ValueError:
        return x

Example:

>>> [try_int(x) for x in  ['sam', '1', 'dad', '21']]
['sam', 1, 'dad', 21]

Edit: If you need to apply the above to a list of lists, why didn't you converted those strings to int while building the nested list?

Anyway, if you need to, it's just a matter of choice on how to iterate over such nested list and apply the method above.

One way for doing that, might be:

>>> list_of_lists = [['aa', '2'], ['bb', '3']]
>>> [[try_int(x) for x in lst] for lst in list_of_lists]
[['aa', 2], ['bb', 3]]

You can obviusly reassign that to list_of_lists:

>>> list_of_lists = [[try_int(x) for x in lst] for lst in list_of_lists]
Sign up to request clarification or add additional context in comments.

4 Comments

@larsmans: Emh... I don't know... I was probably dazzled by the OP map(). I'll update the answer in a moment :)
I've been so bold as to do it for you.
@RikPoggi please look at the edited part, i am trying for the list of that type
@sum2000: You should've stated that from the beginning :) Anyway just iterate over your list_of_list and apply the method above on each sub list.
3

How about using map and lambda

>>> map(lambda x:int(x) if x.isdigit() else x,['sam','1','dad','21'])
['sam', 1, 'dad', 21]

or with List comprehension

>>> [int(x) if x.isdigit() else x for x in ['sam','1','dad','21']]
['sam', 1, 'dad', 21]
>>> 

As mentioned in the comment, as isdigit may not capture negative numbers, here is a refined condition to handle it notable a string is a number if its alphanumeric and not a alphabet :-)

>>> [int(x) if x.isalnum() and not x.isalpha() else x for x in ['sam','1','dad','21']]
['sam', 1, 'dad', 21]

9 Comments

str.isdigit() isn't the right test to see if int() will work, specifically when you can have negative values. Calling int() is the right test.
i am doing l1=[int(x) if x.isdigit() else x for x in l], it is showing error AttributeError: 'list' object has no attribute 'isdigit'
@sum2000 This method only works if all the items in the list are strings. It sounds like some of the items in your list aren't.
How is l defined? can you tell me the result of [type(x) for x in l]
Your updated version is still wrong for negative numbers. '-21'.isalnum() is False. Calling int and handling the error is the only simple solution that always works. Not everything needs to be a one-liner.
|
3

I would create a generator to do it:

def intify(lst):
    for i in lst:
        try:
            i = int(i)
        except ValueError:
            pass
        yield i

lst = ['sam','1','dad','21']
intified_list = list(intify(lst))
# or if you want to modify an existing list
# lst[:] = intify(lst)

If you want this to work on a list of lists, just:

new_list_of_lists = map(list, map(intify, list_of_lists))

6 Comments

The idea is right, but the implementation is not very elegant; the str-to-int conversion and iteration should really be separated as in Rik Poggi's answer.
@larsmans I disagree. I assumed based on the question that this is only going to be used on sequences, so why require the extra step of map? Not everything has to be written in functional programming style. (Also, purely as a bonus, this gives the same result on both Python 2 and Python 3).
map is not needed, but separating iteration from purely per-element conversions, in my experience, leads to much cleaner and more readable code. It's a matter of separating concerns, not my FP fetish ;)
@sum2000 I already updated mine to match. The same basic idea could be used for the other answers.
@agf i tried but only first two intable strings of sublist 1 is converted to int
|
1

For multidimenson lists, use recursive technique may help.

from collections import Iterable
def intify(maybeLst):
    try:
        return int(maybeLst)
    except:
        if isinstance(maybeLst, Iterable) and not isinstance(lst, str):
            return [intify(i) for i in maybeLst] # here we call intify itself!
        else:
            return maybeLst

maybeLst = [[['sam', 2],'1'],['dad','21']]
print intify(maybeLst) 

Comments

0

Use isdigit() to check each character in the string to see if it is a digit.

Example:

mylist = ['foo', '3', 'bar', '9']
t = [ int(item) if item.isdigit() else item for item in mylist ] 
print(t)

2 Comments

See Thomas' comment on the other equivalent answer about why this can be wrong.
Shouldn't "-1" be able to convert to int?
0

Keep all values in the list

l = ['sam', '1', 'dad', '21', '-10']

t = [int(v) if v.lstrip('-').isnumeric() else v for v in l]

print(t)

>>> ['sam', 1, 'dad', 21, -10]

Remove non-numeric values

l = ['sam', '1', 'dad', '21', '-10']

t = [int(v) for v in t if v.lstrip('-').isnumeric()]

print(t)

>>> [1, 21, -10]

Nested list

l = [['aa', '2'], ['bb', '3'], ['sam', '1', 'dad', '21', '-10']]

t = [[int(v) if v.lstrip('-').isnumeric() else v for v in x] for x in l]

print(t)

>>> [['aa', 2], ['bb', 3], ['sam', 1, 'dad', 21, -10]]

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.