Czy wywołać funkcję int () na każdym elemencie listy?

184

Mam listę z ciągami liczbowymi, takimi jak:

numbers = ['1', '5', '10', '8'];

Chciałbym przekonwertować każdy element listy na liczbę całkowitą, więc wyglądałoby to tak:

numbers = [1, 5, 10, 8];

Mógłbym to zrobić za pomocą pętli:

new_numbers = [];
for n in numbers:
    new_numbers.append(int(n));
numbers = new_numbers;

Czy to musi być takie brzydkie? Jestem pewien, że istnieje bardziej pythonowy sposób na zrobienie tego w jednym wierszu kodu. Proszę pomóż mi.

Srebrne światło
źródło
1
Jakiej wersji Pythona używasz?
Mark Byers

Odpowiedzi:

131

W Python 2.x innym podejściem jest użycie map:

numbers = map(int, numbers)

Uwaga: w Python 3.x mapzwraca obiekt mapy, który możesz przekonwertować na listę, jeśli chcesz:

numbers = list(map(int, numbers))
Mark Byers
źródło
11
W Pythonie 3.x mapzwraca iterator zamiast listy, więc należy go zapisać tak, list(map(int, numbers))jakby potrzebna była lista.
kennytm
2
Myślę, że obecnie podejście polegające na zrozumieniu listy jest nieco bardziej uprzywilejowane.
extraneon
3
@extraneon: Tak ... lub rozważ użycie generatora zamiast listy, w zależności od tego, do czego go użyjesz. Zaletą generatora jest to, że jeśli nie będziesz musiał patrzeć na wszystkie elementy, nie będziesz musiał tracić czasu na ich obliczanie z góry.
Mark Byers
4
Mierzone za pomocą timeit w Pythonie 2.7.2: LC: 3.578153133392334, mapa: 4.9065070152282715
AJJ
1
@AJJ: mapma wyższe koszty instalacji, ale w interpretatorze referencyjnym, jeśli funkcja transformacji jest wbudowaną funkcją Pythona zaimplementowaną w C, ma niższy koszt jednostkowy. Testowanie na wejściu tylko czterech wartości nie dostarczy przydatnych informacji na temat skalowania. To powiedziawszy, w moich własnych testach (na Py2.7.12 i Py3.5.2, ten ostatni z list()zawijaniem), Py2 mapwygrał nawet dla czterech elementów wejściowych i traci tylko niewielki margines na Py3; Podejrzewam, że twoje testy zostały wypaczone na korzyść listcomps.
ShadowRanger,
21

tylko punkt

numbers = [int(x) for x in numbers]

zrozumienie listy jest bardziej naturalne, podczas gdy

numbers = map(int, numbers)

jest szybszy.

Prawdopodobnie w większości przypadków nie będzie to miało znaczenia

Przydatna lektura: LP vs mapa

renatopp
źródło
6
Czy nie powinna to być liczba = mapa (int, liczba)?
Karan
9

Jeśli zamierzasz przekazać te liczby całkowite do funkcji lub metody, rozważ ten przykład:

sum(int(x) for x in numbers)

Konstrukcja ta jest celowo niezwykle podobna do opisów list wspomnianych przez adamk. Bez nawiasów kwadratowych nazywa się to wyrażeniem generatora i jest bardzo wydajnym sposobem na przekazanie listy argumentów do metody. Dobra dyskusja jest dostępna tutaj: Wyrażenia generatora vs. Zrozumienie listy

Tim McNamara
źródło
4

Kolejny sposób, aby zrobić to w Pythonie 3:

numbers = [*map(int, numbers)]

zhukovgreen
źródło
1
Czy możesz to wyjaśnić? Nie znam tej składni. Dzięki!
abalter
1
Korzystam z listy rozpakowywania argumentów ( docs.python.org/3/tutorial/… )
zhukovgreen,
Aha, python 3 rzecz. Wydaje się dziwne mieć []listę argumentów. I nie wiedziałem, że możesz przekazać iterator jako listę argumentów. Myślałbym zrobić number = list(map(int, numbers)). Ale dzięki za wyjaśnienie!
abalter
3

Inny sposób,

for i, v in enumerate(numbers): numbers[i] = int(v)
Nick Dandoulakis
źródło
6
OP powiedział pythoniczny
SilentGhost
3
Ten sposób jest bardzo przydatny, jeśli chcesz wykonać operację tylko na niektórych elementach na liście. Nie dotyczy to pytania w tym wątku, ale mogą zdarzyć się przypadki, gdy jest to pomocne
Dikla,
1

Pomyślałem, że skonsoliduję odpowiedzi i pokażę kilka timeit wyników.

Python 2 jest do tego bardzo kiepski, ale mapjest nieco szybszy niż rozumienie.

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

Sam Python 3 jest ponad 4x szybszy, ale konwertuje map obiektu generatora na listę jest wciąż szybsza niż zrozumienie, a tworzenie listy przez rozpakowanie mapgeneratora (dzięki Artem!) Jest jeszcze nieco szybsze.

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

Uwaga: W Pythonie 3 4 elementy wydają się być punktem podziału (3 w Pythonie 2), w którym rozumienie jest nieco szybsze, chociaż rozpakowywanie generatora jest wciąż szybsze niż w przypadku list zawierających więcej niż 1 element.

Jim
źródło