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']]

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
sum2000
  • 1,363
  • 5
  • 21
  • 36
  • 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]`. – Thomas Wouters Mar 26 '12 at 09:31
  • `[int(x) for x in l]` will throw `ValueError`s for non-numeric strings. – Mariusz Jamro Mar 26 '12 at 09: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. – Zahra Sep 08 '17 at 18:48

6 Answers6

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]
Rik Poggi
  • 28,332
  • 6
  • 65
  • 82
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))
agf
  • 171,228
  • 44
  • 289
  • 238
  • 1
    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. – Fred Foo Mar 26 '12 at 09:35
  • @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). – agf Mar 26 '12 at 09:40
  • `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](https://en.wikipedia.org/wiki/Separation_of_concerns), not my FP fetish ;) – Fred Foo Mar 26 '12 at 09:44
  • @sum2000 I already updated mine to match. The same basic idea could be used for the other answers. – agf Mar 26 '12 at 09:49
  • @agf i tried but only first two intable strings of sublist 1 is converted to int – sum2000 Mar 26 '12 at 09:59
  • @sum2000 Post an example that doesn't work. I can't just guess what it is you want. – agf Mar 26 '12 at 10:22
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]
Abhijit
  • 62,056
  • 18
  • 131
  • 204
  • 2
    `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. – Thomas Wouters Mar 26 '12 at 09:29
  • 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 Mar 26 '12 at 09:33
  • @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. – agf Mar 26 '12 at 09:34
  • How is l defined? can you tell me the result of `[type(x) for x in l]` – Abhijit Mar 26 '12 at 09:35
  • 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. – agf Mar 26 '12 at 09:36
  • @agf: Hmm I agree. Let me stop here thinking beyond. – Abhijit Mar 26 '12 at 09:39
  • @Abhijit '[, , , , , , ] ' – sum2000 Mar 26 '12 at 09:39
  • @sum2000: It seems your list is not a list of integers but a bit complex for that. None of the methods mentioned in here will work. Please give the correct format of l. What is the result of `print l` – Abhijit Mar 26 '12 at 09:41
  • @Abhijit i have edited the question and list type is list within a list – sum2000 Mar 26 '12 at 09:43
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) 
Ray
  • 1,647
  • 13
  • 16
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]]
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
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)
Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Mariusz Jamro
  • 30,615
  • 24
  • 120
  • 162