Pobieranie mapy () w celu zwrócenia listy w Pythonie 3.x

523

Próbuję zmapować listę na heks, a następnie użyć listy w innym miejscu. W Pythonie 2.6 było to łatwe:

Odp .: Python 2.6:

>>> map(chr, [66, 53, 0, 94])
['B', '5', '\x00', '^']

Jednak w Pythonie 3.1 powyższe zwraca obiekt mapy.

B: Python 3.1:

>>> map(chr, [66, 53, 0, 94])
<map object at 0x00AF5570>

Jak pobrać zmapowaną listę (jak w A powyżej) w Pythonie 3.x?

Alternatywnie, czy jest na to lepszy sposób? Mój początkowy obiekt listy zawiera około 45 elementów i chciałbym przekonwertować je na hex.

mozami
źródło
2
Bardziej pythonowe jest używanie rozumienia listy . map()został prawie usunięty z języka, ponieważ nie ma powodu, aby używać go do interpretacji listy lub forpętli.
Boris

Odpowiedzi:

771

Zrób to:

list(map(chr,[66,53,0,94]))

W Pythonie 3+ wiele procesów iterujących się nad iteracjami zwraca same iteratory. W większości przypadków kończy się to oszczędzaniem pamięci i powinno przyspieszyć.

Jeśli wszystko, co zamierzasz zrobić, to w końcu iterować tę listę, nie musisz nawet konwertować jej na listę, ponieważ nadal możesz iterować mapobiekt:

# Prints "ABCD"
for ch in map(chr,[65,66,67,68]):
    print(ch)
Tryptyk
źródło
15
Oczywiście możesz też iterować: (chr (x) dla x w [65,66,67,68]). Nie potrzebuje nawet mapy.
hughdbrown
2
@hughdbrown Argumentem za korzystaniem z wersji 3.1 mapbyłaby leniwa ocena podczas iteracji złożonej funkcji, dużych zbiorów danych lub strumieni.
Andrew Keeton,
18
@Andrew faktycznie Hugh posługuje się zrozumieniem generatora, który zrobiłby to samo. Zwróć uwagę na nawiasy zamiast nawiasów kwadratowych.
Tryptyk
5
Alternatywnym rozwiązaniem (szybszym również dla dużych danych wejściowych), gdy znane są wartości ASCII / latin-1, jest wykonywanie masowych konwersji w warstwie C: bytes(sequence_of_ints_in_range_0_to_256).decode('latin-1')co strprzyspiesza dzięki unikaniu wywołań funkcji Pythona dla każdego elementu na korzyść masowej konwersji wszystkie elementy używające tylko wywołań funkcji poziomu C. Możesz owinąć powyższe, listjeśli naprawdę potrzebujesz jednego listz pojedynczych znaków, ale ponieważ strjest już iterowalny dla własnych znaków, jedynym powodem, dla którego to zrobiłeś, jest to, że potrzebujesz zmienności.
ShadowRanger
1
lista (mapa (str, [1,2,3])) podaje „Błąd w argumencie” dla Pythona 3.4.3 na CentOS 7. Funkcja czytania list działa.
Andor
108

Nowy i czysty w Pythonie 3.5:

[*map(chr, [66, 53, 0, 94])]

Dzięki dodatkowym generalizacjom rozpakowywania

AKTUALIZACJA

Zawsze szukając krótszych dróg, odkryłem, że ten działa również:

*map(chr, [66, 53, 0, 94]),

Rozpakowywanie działa również w krotkach. Zwróć uwagę na przecinek na końcu. To sprawia, że ​​jest to krotka 1 element. Oznacza to, że jest to równoważne z(*map(chr, [66, 53, 0, 94]),)

Jest krótszy tylko o jeden znak z wersji z nawiasami listy, ale moim zdaniem lepiej pisać, ponieważ zaczynasz od gwiazdki - składni rozszerzenia, więc myślę, że jest to łagodniejsze. :)

Israel Unterman
źródło
11
@Quelklef list()nie wygląda tak schludnie
Arijoon,
5
@Quelklef: Również podejście do rozpakowywania jest trywialnie szybsze dzięki temu, że nie trzeba szukać listkonstruktora i wywoływać mechanizmu wywoływania funkcji ogólnych. W przypadku długich danych wejściowych nie będzie to miało znaczenia; w skrócie może to mieć duże znaczenie. Używając powyższego kodu z danymi wejściowymi, tupleaby nie był wielokrotnie odtwarzany, ipythonznaki mikrodruku pokazują, że list()podejście do zawijania zajmuje około 20% dłużej niż rozpakowanie. Pamiętaj, że w kategoriach absolutnych mówimy o 150 ns, co jest banalne, ale masz pomysł.
ShadowRanger
Co było nie tak ze starym map? Może z nową nazwą ( lmap?), Jeśli nową wartością domyślną jest zwrócenie iteratora?
Giorgio
1
*map()daje błąd składni na Python 3.6: can't use starred expression here. Musisz umieścić go w list:[ *map() ]
ALH
4
@ALH Przegapiłeś przecinek na końcu polecenia. Łatwy błąd!
LondonRob
103

Dlaczego tego nie robisz:

[chr(x) for x in [66,53,0,94]]

Nazywa się to zrozumieniem listy. Możesz znaleźć wiele informacji w Google, ale tutaj jest link do dokumentacji Pythona (2.6) na temat list . Jednak możesz być bardziej zainteresowany dokumentacją Python 3 .

Mark Rushakoff
źródło
4
Hmmmm Być może w Pythonie musi istnieć ogólny post dotyczący wyrażeń listowych, generatorów, map (), zip () i wielu innych zalet szybkiej iteracji.
hughdbrown,
46
Chyba dlatego, że jest bardziej gadatliwy, musisz napisać dodatkową zmienną (dwa razy) ... Jeśli operacja jest bardziej złożona i kończy się pisanie lambdy, lub musisz też upuścić niektóre elementy, myślę, że zrozumienie jest zdecydowanie lepsze niż mapa + filtr, ale jeśli masz już funkcję, którą chcesz zastosować, mapa jest bardziej zwięzła.
fortran
1
+1: Łatwiejszy do odczytania i pozwala korzystać z funkcji o wielu parametrach
Le Droid
7
map(chr, [66,53,0,94])jest zdecydowanie bardziej zwięzły niż [chr(x) for x in [66,53,0,94]].
Giorgio
znacznie szybciej niż inne odpowiedzi
Evhz
25

Zaletą funkcji powrotu do listy jest oszczędność pisania, zwłaszcza podczas sesji interaktywnych. Możesz zdefiniować lmapfunkcję (na zasadzie python2 imap), która zwraca listę:

lmap = lambda func, *iterable: list(map(func, *iterable))

Wtedy zadzwonienie lmapzamiast mapwykona zadanie: lmap(str, x)jest krótsze o 5 znaków (w tym przypadku 30%) niż list(map(str, x))i na pewno jest krótsze niż [str(v) for v in x]. Możesz także stworzyć podobne funkcje filter.

Do pierwotnego pytania był komentarz:

Proponuję zmienić nazwę na Get map (), aby zwrócić listę w Pythonie 3. *, ponieważ dotyczy ona wszystkich wersji Python3. Czy jest na to sposób? - meawoppl 24 stycznia o 17:58

Można to zrobić, ale to bardzo zły pomysł. Dla zabawy, oto jak możesz ( ale nie powinieneś ) to zrobić:

__global_map = map #keep reference to the original map
lmap = lambda func, *iterable: list(__global_map(func, *iterable)) # using "map" here will cause infinite recursion
map = lmap
x = [1, 2, 3]
map(str, x) #test
map = __global_map #restore the original map and don't do that again
map(str, x) #iterator
Boris Gorelik
źródło
4

Konwertowanie mojego starego komentarza dla lepszej widoczności: dla „lepszego sposobu na zrobienie tego” bez mapcałkowicie, jeśli twoje dane wejściowe są znane jako porządki ASCII, generalnie znacznie szybciej jest konwertować bytesi dekodować la bytes(list_of_ordinals).decode('ascii'). To daje ci jedną strz wartości, ale jeśli potrzebujesz listzmienności lub podobnej, możesz po prostu przekonwertować (i to jeszcze szybciej). Na przykład w ipythonmikrodrukach przekształcających 45 danych wejściowych:

>>> %%timeit -r5 ordinals = list(range(45))
... list(map(chr, ordinals))
...
3.91 µs ± 60.2 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*map(chr, ordinals)]
...
3.84 µs ± 219 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*bytes(ordinals).decode('ascii')]
...
1.43 µs ± 49.7 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... bytes(ordinals).decode('ascii')
...
781 ns ± 15.9 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

Jeśli pozostawisz to jako str, zajmuje około 20% czasu najszybszych maprozwiązań; nawet powrót do listy to wciąż mniej niż 40% najszybszego maprozwiązania. Konwersja zbiorcza przez, bytesa bytes.decodenastępnie konwersja zbiorcza z powrotem listoszczędza dużo pracy, ale jak wspomniano, działa tylko wtedy, gdy wszystkie dane wejściowe są w porządku ASCII (lub porządkami w jednym bajcie na kodowanie specyficzne dla ustawień regionalnych, np latin-1.).

ShadowRanger
źródło
2
list(map(chr, [66, 53, 0, 94]))

map (func, * iterables) -> obiekt mapy Stwórz iterator, który oblicza funkcję przy użyciu argumentów z każdego z iteratów. Zatrzymuje się, gdy wyczerpana zostanie najkrótsza iteracja.

„Zrób iterator”

oznacza, że ​​zwróci iterator.

„który oblicza funkcję przy użyciu argumentów z każdego z iteratorów”

oznacza, że ​​następna funkcja iteratora pobierze jedną wartość z każdej iteracji i przekaże każdą z nich do jednego parametru pozycyjnego funkcji.

Więc dostajesz iterator z funkcji map () i jsut przekazuje go do wbudowanej funkcji list () lub używa wyrażeń listowych.

Ini
źródło
2

Oprócz powyższych odpowiedzi w Python 3, możemy po prostu stworzyć listwartości wynikają z mapjak

li = []
for x in map(chr,[66,53,0,94]):
    li.append(x)

print (li)
>>>['B', '5', '\x00', '^']

Możemy uogólnić na inny przykład, w którym zostałem trafiony, operacje na mapie mogą być również obsługiwane w podobny sposób, jak w przypadku regexproblemu, możemy napisać funkcję, aby uzyskać listelementy do mapy i uzyskać zestaw wyników w tym samym czasie. Dawny.

b = 'Strings: 1,072, Another String: 474 '
li = []
for x in map(int,map(int, re.findall('\d+', b))):
    li.append(x)

print (li)
>>>[1, 72, 474]
Harry_pb
źródło
@miradulo Podejrzewałem, że w Pythonie 2 lista została zwrócona, ale w Pythonie 3 zwracany jest tylko typ i próbowałem podać w tym samym formacie. Jeśli uważasz, że jest to niepotrzebne, być może ludzie tacy jak ja mogą go uznać za przydatny i dlatego dodałem.
Harry_pb
2
Kiedy jest już zrozumienie listy, funkcja listy i odpowiedź na rozpakowanie, wyraźna pętla for nie dodaje dużo IMHO.
miradulo
1

Możesz spróbować uzyskać listę z obiektu mapy, po prostu iterując każdy element w obiekcie i przechowując go w innej zmiennej.

a = map(chr, [66, 53, 0, 94])
b = [item for item in a]
print(b)
>>>['B', '5', '\x00', '^']
Akshay Satpaise
źródło
0

Używając rozumienia list w Pythonie i podstawowej funkcji mapy, można to zrobić również:

chi = [x for x in map(chr,[66,53,0,94])]

darszan ks
źródło
lista chi będzie zawierać wartość ASIC podanych elementów.
darszan ks