I have a list with numeric strings, like so:
numbers = ['1', '5', '10', '8'];
I would like to convert every list element to integer, so it would look like this:
numbers = [1, 5, 10, 8];
I could do it using a loop, like so:
new_numbers = [];
for n in numbers:
new_numbers.append(int(n));
numbers = new_numbers;
Does it have to be so ugly? I'm sure there is a more pythonic way to do this in a one line of code. Please help me out.
This is what list comprehensions are for:
numbers = [ int(x) for x in numbers ]
In Python 2.x another approach is to use map
:
numbers = map(int, numbers)
Note: in Python 3.x map
returns a map object which you can convert to a list if you want:
numbers = list(map(int, numbers))
map
returns an iterator instead of a list, so it needs to be written as list(map(int, numbers))
if a list is needed.
map
has higher setup overhead, but on the reference interpreter, if the transform function is a Python built-in function implemented in C, it has a lower per item cost. Testing on an input of only four values will not provide useful information on scaling. That said, in my own tests (on Py2.7.12 and Py3.5.2, the latter with list()
wrapping), Py2 with map
won even for four element inputs, and loses by only a tiny margin on Py3; I suspect your tests were warped in favor of listcomps.
just a point,
numbers = [int(x) for x in numbers]
the list comprehension is more natural, while
numbers = map(int, numbers)
is faster.
Probably this will not matter in most cases
Useful read: LP vs map
If you are intending on passing those integers to a function or method, consider this example:
sum(int(x) for x in numbers)
This construction is intentionally remarkably similar to list comprehensions mentioned by adamk. Without the square brackets, it's called a generator expression, and is a very memory-efficient way of passing a list of arguments to a method. A good discussion is available here: Generator Expressions vs. List Comprehension
Another way to make it in Python 3:
numbers = [*map(int, numbers)]
However ideally you may be happy just with map, as it is returning an iterator:
numbers = map(int, numbers)
[]
take an argument list. And, I didn't know you could pass an iterator as an argument list. I would have thought to do number = list(map(int, numbers))
. But thanks for the explanation!
Another way,
for i, v in enumerate(numbers): numbers[i] = int(v)
Thought I'd consolidate the answers and show some timeit
results.
Python 2 sucks pretty bad at this, but map
is a bit faster than comprehension.
Python 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:42:59) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import timeit
>>> setup = """import random
random.seed(10)
l = [str(random.randint(0, 99)) for i in range(100)]"""
>>> timeit.timeit('[int(v) for v in l]', setup)
116.25092001434314
>>> timeit.timeit('map(int, l)', setup)
106.66044823117454
Python 3 is over 4x faster by itself, but converting the map
generator object to a list is still faster than comprehension, and creating the list by unpacking the map
generator (thanks Artem!) is slightly faster still.
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 17:54:52) [MSC v.1900 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import timeit
>>> setup = """import random
random.seed(10)
l = [str(random.randint(0, 99)) for i in range(100)]"""
>>> timeit.timeit('[int(v) for v in l]', setup)
25.133059591551955
>>> timeit.timeit('list(map(int, l))', setup)
19.705547827217515
>>> timeit.timeit('[*map(int, l)]', setup)
19.45838406513076
Note: In Python 3, 4 elements seems to be the crossover point (3 in Python 2) where comprehension is slightly faster, though unpacking the generator is still faster than either for lists with more than 1 element.
It may also be worth noting that NumPy will do this on the fly when creating an array:
import numpy as np
numbers = ['1', '5', '10', '8']
numbers = np.array(numbers,
dtype=int)
numbers
array([ 1, 5, 10, 8])
Success story sharing