Mendapatkan peta () untuk mengembalikan daftar dengan Python 3.x

523

Saya mencoba memetakan daftar ke hex, dan kemudian menggunakan daftar di tempat lain. Dalam python 2.6, ini mudah:

A: Python 2.6:

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

Namun, dalam Python 3.1, di atas mengembalikan objek peta.

B: Python 3.1:

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

Bagaimana cara mengambil daftar yang dipetakan (seperti pada A di atas) di Python 3.x?

Atau, apakah ada cara yang lebih baik untuk melakukan ini? Objek daftar awal saya memiliki sekitar 45 item dan id ingin mengubahnya menjadi hex.

mozami
sumber
2
Lebih pythonic untuk menggunakan daftar pemahaman . map()itu hampir dihapus dari bahasa karena tidak ada alasan untuk menggunakannya lebih dari satu daftar pemahaman atau forlingkaran.
Boris

Jawaban:

771

Melakukan hal ini:

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

Dalam Python 3+, banyak proses yang beralih dari iterables mengembalikan iterator sendiri. Dalam kebanyakan kasus, ini akhirnya menghemat memori, dan harus membuat segalanya berjalan lebih cepat.

Jika semua yang akan Anda lakukan adalah beralih pada daftar ini pada akhirnya, Anda tidak perlu mengubahnya menjadi daftar, karena Anda masih dapat beralih ke mapobjek seperti:

# Prints "ABCD"
for ch in map(chr,[65,66,67,68]):
    print(ch)
Triptych
sumber
15
Tentu saja, Anda dapat mengulangi hal ini juga: (chr (x) untuk x dalam [65,66,67,68]). Bahkan tidak perlu peta.
hughdbrown
2
@ hughdbrown Argumen untuk menggunakan 3.1 mapakan menjadi evaluasi malas ketika iterasi pada fungsi yang kompleks, set data yang besar, atau stream.
Andrew Keeton
18
@ Andrew sebenarnya Hugh sedang menggunakan pemahaman generator yang akan melakukan hal yang sama. Perhatikan tanda kurung alih-alih tanda kurung.
Triptych
5
Solusi alternatif (lebih cepat untuk input besar juga) ketika nilainya dikenal sebagai ASCII / latin-1 adalah dengan melakukan konversi massal pada lapisan C: bytes(sequence_of_ints_in_range_0_to_256).decode('latin-1')yang membuat strlebih cepat dengan menghindari panggilan fungsi Python untuk setiap elemen yang mendukung konversi massal dari semua elemen hanya menggunakan panggilan fungsi level C. Anda dapat membungkus di atas listjika Anda benar-benar membutuhkan listkarakter individu, tetapi karena strsudah dapat diubah karakternya sendiri, satu-satunya alasan Anda akan melakukannya adalah jika Anda membutuhkan kemampuan berubah-ubah.
ShadowRanger
1
daftar (peta (str, [1,2,3])) memberikan "Kesalahan dalam argumen" untuk Python 3.4.3 pada CentOS 7. Pemahaman daftar berfungsi.
Andor
108

Baru dan rapi dalam Python 3.5:

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

Berkat Generalisasi Pembongkaran Tambahan

MEMPERBARUI

Selalu mencari cara yang lebih pendek, saya menemukan ini juga berfungsi:

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

Membongkar karya di tuple juga. Perhatikan koma di bagian akhir. Ini membuatnya menjadi tupel dari 1 elemen. Artinya, ini setara dengan(*map(chr, [66, 53, 0, 94]),)

Ini lebih pendek dengan hanya satu karakter dari versi dengan tanda kurung, tetapi, menurut pendapat saya, lebih baik untuk menulis, karena Anda mulai dengan asterisk - sintaksis ekspansi, jadi saya merasa lebih lembut di pikiran. :)

Israel Unterman
sumber
11
@Quelklef list()tidak terlihat rapi
Arijoon
5
@Quelklef: Juga, pendekatan membongkar sepele lebih cepat berkat tidak perlu mencari listkonstruktor dan memanggil mesin panggilan fungsi umum. Untuk input panjang, itu tidak masalah; untuk yang singkat, itu bisa membuat perbedaan besar. Menggunakan kode di atas dengan input sebagai tuplesehingga tidak berulang kali direkonstruksi, ipythonmicrobenchmark menunjukkan list()pendekatan pembungkus membutuhkan sekitar 20% lebih lama daripada membongkar. Pikiran Anda, secara absolut, kita berbicara tentang 150 ns, yang sepele, tetapi Anda mendapatkan idenya.
ShadowRanger
Apa yang salah dengan yang lama map? Mungkin dengan nama baru ( lmap?) Jika default baru adalah mengembalikan iterator?
Giorgio
1
*map()memberikan kesalahan sintaks pada Python 3.6: can't use starred expression here. Anda harus memasukkannya ke dalam list:[ *map() ]
ALH
4
@ALH Anda melewatkan koma di akhir perintah. Kesalahan mudah dibuat!
LondonRob
103

Mengapa Anda tidak melakukan ini:

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

Ini disebut pemahaman daftar. Anda dapat menemukan banyak informasi di Google, tetapi di sini ada tautan ke dokumentasi Python (2.6) tentang daftar pemahaman . Anda mungkin lebih tertarik pada dokumentasi Python 3 .

Mark Rushakoff
sumber
4
Hmmmm. Mungkin perlu ada posting umum pada daftar pemahaman, generator, peta (), zip (), dan banyak iterasi cepat lainnya dalam python.
hughdbrown
46
Saya kira karena lebih verbose, Anda harus menulis variabel tambahan (dua kali) ... Jika operasi lebih kompleks dan Anda akhirnya menulis lambda, atau Anda perlu juga menjatuhkan beberapa elemen, saya pikir pemahaman secara definitif lebih baik daripada peta + filter, tetapi jika Anda sudah memiliki fungsi yang ingin Anda terapkan, peta lebih ringkas.
fortran
1
+1: Lebih mudah dibaca & memungkinkan Anda menggunakan fungsi dengan banyak parameter
Le Droid
7
map(chr, [66,53,0,94])jelas lebih ringkas daripada [chr(x) for x in [66,53,0,94]].
Giorgio
jauh lebih cepat daripada jawaban lainnya
Evhz
25

Fungsi peta daftar-kembali memiliki keuntungan menghemat pengetikan, terutama selama sesi interaktif. Anda dapat mendefinisikan lmapfungsi (pada analogi python2's imap) yang mengembalikan daftar:

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

Maka menelepon lmapbukannya mapakan melakukan pekerjaan: lmap(str, x)lebih pendek dengan 5 karakter (30% dalam kasus ini) daripada list(map(str, x))dan tentu saja lebih pendek dari [str(v) for v in x]. Anda juga dapat membuat fungsi serupa filter.

Ada komentar untuk pertanyaan asli:

Saya akan menyarankan ganti nama untuk Mendapatkan peta () untuk mengembalikan daftar dalam Python 3. * sebagaimana berlaku untuk semua versi Python3. Apakah ada cara untuk melakukan ini? - meawoppl 24 Jan pukul 17:58

Hal ini mungkin untuk melakukan itu, tapi itu adalah ide yang sangat buruk. Hanya untuk bersenang-senang, inilah cara Anda ( tetapi tidak seharusnya ) melakukannya:

__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
sumber
4

Mengonversi komentar lama saya untuk visibilitas yang lebih baik: Untuk "cara yang lebih baik untuk melakukan ini" tanpa mapsepenuhnya, jika input Anda dikenal sebagai ordinal ASCII, umumnya jauh lebih cepat untuk mengonversi bytesdan mendekodekan, ala bytes(list_of_ordinals).decode('ascii'). Itu memberi Anda strnilai-nilai, tetapi jika Anda membutuhkan kemampuan listberubah-ubah atau sejenisnya, Anda bisa mengubahnya (dan itu masih lebih cepat). Misalnya, dalam ipythonmicrobenchmarks, mengubah 45 input:

>>> %%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)

Jika Anda membiarkannya sebagai str, dibutuhkan ~ 20% dari waktu mapsolusi tercepat ; bahkan mengubah kembali ke daftar itu masih kurang dari 40% dari mapsolusi tercepat . Konversi massal melalui bytesdan bytes.decodekemudian konversi massal untuk listmenyimpan banyak pekerjaan, tetapi seperti disebutkan, hanya berfungsi jika semua input Anda adalah ASCII ordinals (atau ordinals dalam beberapa byte per karakter pengkodean spesifik lokal karakter, misalnya latin-1).

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

map (func, * iterables) -> object map Buat iterator yang menghitung fungsi menggunakan argumen dari masing-masing iterables. Berhenti ketika program terpendek habis.

"Buat iterator"

berarti akan mengembalikan iterator.

"yang menghitung fungsi menggunakan argumen dari masing-masing iterables"

berarti bahwa () fungsi iterator berikutnya akan mengambil satu nilai dari setiap iterables dan meneruskannya masing-masing ke satu parameter posisi fungsi.

Jadi Anda mendapatkan iterator dari map () funtion dan hanya meneruskannya ke list () fungsi builtin atau menggunakan pemahaman daftar.

Ini
sumber
2

Selain jawaban di atas Python 3, kami dapat dengan mudah membuat listnilai hasil dari a mapsebagai

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

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

Kita dapat menggeneralisasi dengan contoh lain di mana saya dikejutkan, operasi pada peta juga dapat ditangani dengan cara yang sama seperti dalam regexmasalah, kita dapat menulis fungsi untuk mendapatkan listitem untuk dipetakan dan mendapatkan hasil yang ditetapkan pada waktu yang sama. Ex.

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
sumber
@miradulo Saya kira dalam Python 2, daftar dikembalikan, tetapi dalam Python 3, hanya tipe yang dikembalikan dan saya hanya mencoba untuk memberikan dalam format yang sama. Jika Anda pikir itu tidak perlu, mungkin ada orang seperti saya yang dapat menemukannya berguna dan itulah sebabnya saya menambahkan.
Harry_pb
2
Ketika sudah ada pemahaman daftar, fungsi daftar, dan jawaban membongkar, eksplisit untuk loop tidak menambah banyak IMHO.
miradulo
1

Anda dapat mencoba mendapatkan daftar dari objek peta dengan hanya mengulangi setiap item dalam objek dan menyimpannya dalam variabel yang berbeda.

a = map(chr, [66, 53, 0, 94])
b = [item for item in a]
print(b)
>>>['B', '5', '\x00', '^']
Akshay Satpaise
sumber
0

Menggunakan pemahaman daftar dalam python dan utilitas fungsi peta dasar, orang dapat melakukan ini juga:

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

darshan ks
sumber
Daftar chi akan berisi, nilai ASIC dari elemen yang diberikan.
darshan ks