Python 3.x'te liste döndürmek için harita () alma


523

Bir listeyi onaltılık olarak eşlemeye çalışıyorum ve sonra listeyi başka bir yerde kullanıyorum. Python 2.6'da bu kolaydı:

A: Python 2.6:

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

Ancak, Python 3.1, yukarıdaki bir harita nesnesi döndürür.

B: Python 3.1:

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

Python 3.x'te eşlenen listeyi ( yukarıdaki A'da olduğu gibi) nasıl alabilirim ?

Alternatif olarak, bunu yapmanın daha iyi bir yolu var mı? İlk liste nesnemde yaklaşık 45 öğe var ve bunları onaltılık biçime dönüştürmek istiyorum.


2
Bir liste kavrayışı kullanmak daha pitoniktir . map()bir dil anlama veya fordöngü üzerinde kullanmak için hiçbir neden olmadığı için neredeyse dilden kaldırıldı .
Boris

Yanıtlar:


771

Bunu yap:

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

Python 3 + 'da, yinelenebilirler üzerinde yinelenen birçok işlem yineleyicileri kendileri döndürür. Çoğu durumda, bu bellek tasarrufu sağlar ve işleri daha hızlı hale getirmelidir.

Tek yapmanız gereken sonunda bu liste üzerinde tekrarlamaksa, listeye dönüştürmeye bile gerek yoktur, çünkü yine de mapnesne üzerinde tekrarlayabilirsiniz :

# Prints "ABCD"
for ch in map(chr,[65,66,67,68]):
    print(ch)

15
Elbette bunun üzerinde de yineleme yapabilirsiniz: ([65,66,67,68] 'de x için chr (x)). Haritaya bile ihtiyacı yok.
hughdbrown

2
@hughdbrown 3.1'leri kullanma argümanı, mapkarmaşık bir işlev, büyük veri kümeleri veya akışlarda yineleme yaparken tembel bir değerlendirme olacaktır.
Andrew Keeton

18
@Andrew aslında Hugh aynı şeyi yapacak bir jeneratör kavrayışı kullanıyor. Köşeli parantez yerine parantezlere dikkat edin.
Triptik

5
Değerlerin ASCII / latin-1 olduğu bilindiğinde alternatif çözüm (büyük girişler için daha hızlı) C katmanında toplu dönüşümler yapmaktır: bytes(sequence_of_ints_in_range_0_to_256).decode('latin-1')bu, strtoplu bir dönüşüm lehine her öğe için Python işlev çağrılarından kaçınarak daha hızlı hale getirir . sadece C seviyesi fonksiyon çağrılarını kullanan tüm elemanlar. Tek tek karakterlerden birine listgerçekten ihtiyacınız varsa , yukarıdakileri sarabilirsiniz list, ancak strzaten kendi karakterlerinden bir yinelenebilir olduğundan, bunu yapmanızın tek nedeni değişebilirliğe ihtiyacınız varsa.
ShadowRanger

1
list (harita (str, [1,2,3])), CentOS 7'de Python 3.4.3 için "Bağımsız değişkende hata" verir. Liste anlama çalışmaları.
Andor

108

Python 3.5'te yeni ve temiz:

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

Sayesinde Ek Ambalajın açılması Genellemelerinin

GÜNCELLEME

Her zaman daha kısa yollar aramanın, bunun da işe yaradığını keşfettim:

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

Ambalajdan çıkarma tuples ile de çalışır. Sonunda virgül olduğuna dikkat edin. Bu onu 1 elemandan oluşan bir demet yapar. Yani,(*map(chr, [66, 53, 0, 94]),)

Liste parantezleri içeren sürümden sadece bir karakter daha kısadır, ancak bence, yazmak daha iyidir, çünkü yıldız işaretiyle (genişleme sözdizimi) hemen başlarsınız, bu yüzden akılda daha yumuşak olduğunu hissediyorum. :)


11
@Quelklef list()düzgün görünmüyor
Arijoon

5
@Quelklef: Ayrıca, kurucuya bakmaya listve genel işlev çağrı makinelerini çağırmaya gerek duymadığından, açma yaklaşımı son derece hızlıdır . Uzun bir girdi için önemli değil; kısaca büyük bir fark yaratabilir. Yukarıdaki kodu tupletekrar tekrar yapılandırılmayacak şekilde girişle birlikte kullanan ipythonmikrobenk işaretler, list()sarma yaklaşımının ambalajdan çıkarılmasından yaklaşık% 20 daha uzun sürdüğünü gösterir . Unutmayın, mutlak olarak, 150 ns hakkında konuşuyoruz, bu önemsiz, ama fikri anlıyorsunuz.
ShadowRanger

Eskisi ile ilgili sorun neydi map? Belki lmapyeni varsayılan bir yineleyici döndürmek için yeni bir adla ( ?)?
Giorgio

1
*map()üzerinde sözdizimi hatası veriyor Python 3.6: can't use starred expression here. Bir list[ *map() ]
şeye

4
@ALH Komutun sonunda virgül atladınız. Kolay hata!
LondonRob

103

Bunu neden yapmıyorsunuz:

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

Buna liste kavraması denir. Google'da bol miktarda bilgi bulabilirsiniz, ancak liste anlaşmalarıyla ilgili Python (2.6) belgelerine bağlantı . Yine de Python 3 belgeseliyle daha fazla ilgilenebilirsiniz .


4
Hmmmm. Belki de python'da liste kavrayışları, jeneratörler, harita (), zip () ve diğer birçok hızlı yineleme iyiliği hakkında genel bir yazı olması gerekir.
hughdbrown

46
Sanırım daha ayrıntılı, ekstra bir değişken yazmanız gerekiyor (iki kez) ... İşlem daha karmaşıksa ve bir lambda yazıyorsanız veya bazı öğeleri düşürmeniz gerekiyorsa, bence bir kavrama kesinlikle daha iyidir bir harita + filtreden daha fazladır, ancak uygulamak istediğiniz işleve zaten sahipseniz, harita daha özlüdür.
fortran

1
+1: Daha kolay okunabilir ve birçok parametreye sahip işlevleri kullanmanıza izin verir
Le Droid

7
map(chr, [66,53,0,94])kesinlikle daha özlü [chr(x) for x in [66,53,0,94]].
Giorgio

diğer cevaplardan çok daha hızlı
Evhz

25

Liste geri dönen harita işlevi, özellikle etkileşimli oturumlarda yazmayı kaydetme avantajına sahiptir. Listeyi döndüren lmapişlevi (python2'lerin benzetmesinde) tanımlayabilirsiniz imap:

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

Sonra lmapyerine çağrı mapyapmak işi yapacak: lmap(str, x)5 karakter daha kısadır (bu durumda% 30) list(map(str, x))ve kesinlikle daha kısadır [str(v) for v in x]. Siz de benzer işlevler oluşturabilirsiniz filter.

Orijinal soruya bir yorum yapıldı:

Tüm Python3 sürümleri için geçerli olduğu için Python 3'te bir liste döndürmek için Harita almak () için bir yeniden adlandırma öneririm. Bunu yapmanın bir yolu var mı? - meawoppl 24 Ocak, 17:58

Bunu yapmak mümkündür, ama bu çok kötü bir fikir. Sadece eğlence için, bunu nasıl yapabilirsiniz ( ama yapmamalısınız ):

__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

4

Eski yorumumu daha iyi görünürlük için dönüştürme : "Bunu yapmanın daha iyi bir yolu" maptamamen olmadan , girdilerinizin ASCII ordinalleri olduğu biliniyorsa, genellikle bir la'ya dönüştürmek bytesve kodunu çözmek çok daha hızlıdır bytes(list_of_ordinals).decode('ascii'). Bu size strdeğerlerden birini getirir, ancak listdeğişebilirlik veya benzerine ihtiyacınız varsa , onu dönüştürebilirsiniz (ve yine de daha hızlıdır). Örneğin, ipython45 girişi dönüştüren mikro işaretlerde:

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

Bir olarak bırakırsanız str, en hızlı mapçözümlerin süresinin ~% 20'sini alır ; listeye geri dönse bile hala en hızlı mapçözümün % 40'ından az . Toplu dönüştürme bytesve bytes.decodedaha sonra toplu dönüştürme list, çok iş tasarrufu sağlar, ancak belirtildiği gibi, yalnızca tüm girişleriniz ASCII ordinalleri (veya karakter yerel ayarına özgü kodlama başına bir bayttaki ordinaller latin-1) olduğunda çalışır.


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

map (func, * iterables) -> map nesnesi Her yinelemeden bağımsız değişkenleri kullanarak işlevi hesaplayan bir yineleyici yapın. En kısa yinelenebilir bittiğinde durur.

"Yineleyici yap"

bir yineleyici döndüreceği anlamına gelir.

"yinelemelerin her birinden bağımsız değişkenler kullanarak işlevi hesaplar"

yineleyicinin sonraki () işlevinin her yinelenebilir öğenin bir değerini alacağı ve her birini işlevin bir konum parametresine geçireceği anlamına gelir.

Böylece map () işlevinden bir yineleyici alırsınız ve jsut list () yerleşik işlevine iletir veya liste kavrayışlarını kullanır.


2

Yukarıdaki cevaplara ek olarak Python 3, biz sadece bir yaratabilir listbir gelen sonuç değerlerinin mapolarak

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

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

Vurulduğum başka bir örnekle genelleştirebiliriz, haritadaki işlemler de regexproblem gibi benzer şekilde ele alınabilir, listeşlenecek öğeleri elde etmek ve aynı zamanda sonuç kümesi almak için işlev yazabiliriz . Ör.

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]

@miradulo Ben Python 2, bir liste döndürüldü gerekiyordu, ama Python 3, sadece türü döndürülür ve ben sadece aynı biçimde vermeye çalıştım. Bunun gereksiz olduğunu düşünüyorsanız, belki benim gibi yararlı bulabilecek insanlar var ve bu yüzden ekledim.
Harry_pb

2
Zaten bir liste kavrama, bir liste işlevi ve bir açma cevabı varsa, bir döngü için açık bir IMHO eklemez.
miradulo

1

Nesnedeki her öğeyi yineleyerek ve farklı bir değişkende saklayarak harita nesnesinden bir liste almayı deneyebilirsiniz.

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

0

Python ve temel harita fonksiyonu yardımcı programında liste kavrayışı kullanarak, bunu da yapabilirsiniz:

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


chi listesi, verilen elemanların ASIC değerini içerecektir.
darshan ks
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.