Lấy bản đồ () để trả về danh sách trong Python 3.x


523

Tôi đang cố gắng ánh xạ một danh sách thành hex, và sau đó sử dụng danh sách đó ở nơi khác. Trong python 2.6, điều này thật dễ dàng:

A: Python 2.6:

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

Tuy nhiên, trong Python 3.1, phần trên trả về một đối tượng bản đồ.

B: Python 3.1:

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

Làm cách nào để truy xuất danh sách được ánh xạ (như trong A ở trên) trên Python 3.x?

Ngoài ra, có một cách tốt hơn để làm điều này? Đối tượng danh sách ban đầu của tôi có khoảng 45 mục và id muốn chuyển đổi chúng thành hex.


2
Đó là nhiều pythonic để sử dụng một sự hiểu biết danh sách . map()đã gần như bị xóa khỏi ngôn ngữ vì không có lý do để sử dụng nó qua việc hiểu danh sách hoặc forvòng lặp.
Boris

Câu trả lời:


771

Làm cái này:

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

Trong Python 3+, nhiều quá trình lặp qua các lần lặp trả về chính các trình lặp đó. Trong hầu hết các trường hợp, điều này kết thúc việc tiết kiệm bộ nhớ và sẽ khiến mọi thứ diễn ra nhanh hơn.

Nếu cuối cùng tất cả những gì bạn sẽ làm là lặp lại danh sách này, thậm chí không cần phải chuyển đổi nó thành một danh sách, bởi vì bạn vẫn có thể lặp lại mapđối tượng như vậy:

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

15
Tất nhiên, bạn cũng có thể lặp lại điều này: (chr (x) cho x trong [65,66,67,68]). Nó thậm chí không cần bản đồ.
hughdbrown

2
@hughdbrown Đối số cho việc sử dụng 3.1 mapsẽ là đánh giá lười biếng khi lặp trên một hàm phức tạp, tập dữ liệu lớn hoặc luồng.
Andrew Keeton

18
@Andrew thực sự Hugh đang hiểu một máy phát điện sẽ làm điều tương tự. Lưu ý dấu ngoặc đơn thay vì dấu ngoặc vuông.
Triptych

5
Giải pháp thay thế (cũng nhanh hơn cho các đầu vào lớn) khi các giá trị được biết là ASCII / latin-1 sẽ thực hiện chuyển đổi hàng loạt ở lớp C: bytes(sequence_of_ints_in_range_0_to_256).decode('latin-1')giúp thực hiện strnhanh hơn bằng cách tránh các lệnh gọi hàm Python cho từng phần tử có lợi cho chuyển đổi hàng loạt tất cả các yếu tố chỉ sử dụng các cuộc gọi chức năng cấp C. Bạn có thể gói những thứ ở trên listnếu bạn thực sự cần một listtrong số các ký tự riêng lẻ, nhưng vì strđã có thể lặp lại các ký tự của chính nó, lý do duy nhất bạn làm như vậy là nếu bạn cần khả năng biến đổi.
ShadowRanger

1
list (map (str, [1,2,3])) đưa ra "Lỗi trong đối số" cho Python 3.4.3 trên CentOS 7. Công việc hiểu danh sách.
Andor

108

Mới và gọn gàng trong Python 3.5:

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

Nhờ các khái quát hóa giải nén bổ sung

CẬP NHẬT

Luôn luôn tìm kiếm những cách ngắn hơn, tôi phát hiện ra cách này cũng hoạt động:

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

Giải nén hoạt động trong tuples quá. Lưu ý dấu phẩy ở cuối. Điều này làm cho nó một tuple của 1 phần tử. Đó là, nó tương đương với(*map(chr, [66, 53, 0, 94]),)

Nó ngắn hơn chỉ bằng một char từ phiên bản có dấu ngoặc đơn, nhưng theo tôi, tốt hơn là viết, bởi vì bạn bắt đầu ngay trước dấu hoa thị - cú pháp mở rộng, vì vậy tôi cảm thấy nó nhẹ nhàng hơn. :)


11
@Quelklef list()trông không gọn gàng
Arijoon

5
@Quelklef: Ngoài ra, cách tiếp cận giải nén nhanh hơn đáng kể nhờ không cần tra cứu hàm listtạo và gọi máy móc chức năng gọi chung. Đối với một đầu vào dài, nó sẽ không thành vấn đề; đối với một ngắn, nó có thể tạo ra một sự khác biệt lớn. Sử dụng mã ở trên với đầu vào như tuplevậy để nó không được xây dựng lại nhiều lần, các dấu hiệu ipythonvi mô cho thấy list()phương pháp gói mất nhiều thời gian hơn khoảng 20% ​​so với giải nén. Nói một cách tuyệt đối, chúng tôi đang nói về 150 ns, điều này không quan trọng, nhưng bạn hiểu ý.
ShadowRanger

Điều gì đã sai với cái cũ map? Có thể với một tên mới ( lmap?) Nếu mặc định mới là trả về một iterator?
Giorgio

1
*map()đưa ra lỗi cú pháp trên Python 3.6: can't use starred expression here. Bạn cần đặt nó vào list:[ *map() ]
ALH

4
@ALH Bạn đã bỏ lỡ dấu phẩy ở cuối lệnh. Dễ mắc sai lầm!
LondonRob

103

Tại sao bạn không làm điều này:

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

Nó được gọi là một sự hiểu biết danh sách. Bạn có thể tìm thấy nhiều thông tin trên Google, nhưng đây là liên kết đến tài liệu Python (2.6) về hiểu biết danh sách . Mặc dù vậy, bạn có thể quan tâm nhiều hơn đến thông tin Python 3 .


4
Hừm. Có lẽ cần phải có một bài đăng chung về hiểu biết danh sách, trình tạo, map (), zip () và rất nhiều tính tốt lặp lại nhanh chóng khác trong python.
hughdbrown

46
Tôi đoán bởi vì nó dài dòng hơn, bạn phải viết thêm một biến (hai lần) ... Nếu thao tác phức tạp hơn và cuối cùng bạn viết lambda, hoặc bạn cũng cần bỏ một số yếu tố, tôi nghĩ rằng việc hiểu rõ ràng là tốt hơn hơn là bộ lọc + bản đồ, nhưng nếu bạn đã có chức năng bạn muốn áp dụng, bản đồ sẽ gọn gàng hơn.
fortran

1
+1: Dễ đọc hơn và cho phép bạn sử dụng các chức năng với nhiều tham số
Le Droid

7
map(chr, [66,53,0,94])chắc chắn là ngắn gọn hơn [chr(x) for x in [66,53,0,94]].
Giorgio

cách nhanh hơn các câu trả lời khác
Evhz

25

Chức năng bản đồ trả về danh sách có lợi thế là tiết kiệm gõ, đặc biệt là trong các phiên tương tác. Bạn có thể định nghĩa lmaphàm (trên sự tương tự của python2 imap) trả về danh sách:

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

Sau đó, gọi lmapthay vì mapsẽ thực hiện công việc: lmap(str, x)ngắn hơn 5 ký tự (trong trường hợp này là 30%) list(map(str, x))và chắc chắn là ngắn hơn [str(v) for v in x]. Bạn có thể tạo các chức năng tương tự cho filterquá.

Có một bình luận cho câu hỏi ban đầu:

Tôi sẽ đề nghị đổi tên thành Bắt bản đồ () để trả về danh sách trong Python 3. * vì nó áp dụng cho tất cả các phiên bản Python3. Có cách nào để làm việc này không? - meawoppl ngày 24 tháng 1 lúc 17:58

Đó khả năng để làm điều đó, nhưng nó là một ý kiến tồi. Để giải trí, đây là cách bạn có thể ( nhưng không nên ) làm điều đó:

__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

Chuyển đổi nhận xét cũ của tôi để có khả năng hiển thị tốt hơn: Đối với "cách tốt hơn để làm điều này" mà không maphoàn toàn, nếu đầu vào của bạn được gọi là quy tắc ASCII, thì việc chuyển đổi bytesvà giải mã thường nhanh hơn nhiều bytes(list_of_ordinals).decode('ascii'). Điều đó mang lại cho bạn một strtrong những giá trị, nhưng nếu bạn cần một khả năng listbiến đổi hoặc tương tự, bạn có thể chuyển đổi nó (và nó vẫn nhanh hơn). Ví dụ: trong ipythonmicrobenchmark chuyển đổi 45 đầu vào:

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

Nếu bạn để nó như một str, nó sẽ mất ~ 20% thời gian của các mapgiải pháp nhanh nhất ; thậm chí chuyển đổi trở lại danh sách, nó vẫn chưa đến 40% mapgiải pháp nhanh nhất . Chuyển đổi hàng loạt qua bytesbytes.decodesau đó chuyển đổi hàng loạt trở lại để listtiết kiệm rất nhiều công việc, nhưng như đã lưu ý, chỉ hoạt động nếu tất cả các đầu vào của bạn là các lệnh ASCII (hoặc các lệnh trong một byte cho mỗi ký tự mã hóa cụ thể, ví dụ latin-1).


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

map (func, * iterables) -> map object Tạo một iterator tính toán hàm bằng các đối số từ mỗi iterables. Dừng khi lặp lại ngắn nhất là hết.

"Tạo một vòng lặp"

có nghĩa là nó sẽ trả về một iterator.

"tính toán hàm bằng cách sử dụng các đối số từ mỗi lần lặp"

có nghĩa là hàm next () của iterator sẽ lấy một giá trị của mỗi iterables và chuyển từng giá trị đó cho một tham số vị trí của hàm.

Vì vậy, bạn nhận được một iterator từ funtion map () và jsut chuyển nó vào hàm listin (list) hoặc sử dụng khả năng hiểu danh sách.


2

Ngoài câu trả lời ở trên Python 3, chúng tôi chỉ đơn giản là có thể tạo ra một listgiá trị kết quả từ một mapnhư

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

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

Chúng tôi có thể khái quát bằng một ví dụ khác khi tôi bị tấn công, các thao tác trên bản đồ cũng có thể được xử lý theo cách tương tự như trong regexvấn đề, chúng tôi có thể viết chức năng để lấy listcác mục để lập bản đồ và đặt kết quả cùng một lúc. Ví dụ.

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 Tôi giả sử trong Python 2, một danh sách đã được trả về, nhưng trong Python 3, chỉ có loại được trả về và tôi chỉ cố gắng đưa ra định dạng tương tự. Nếu bạn nghĩ rằng nó không cần thiết, có lẽ những người như tôi có thể thấy nó hữu ích và đó là lý do tại sao tôi thêm vào.
Harry_pb

2
Khi đã có một sự hiểu biết danh sách, một chức năng danh sách và một câu trả lời giải nén, một vòng lặp rõ ràng không thêm nhiều IMHO.
miradulo

1

Bạn có thể thử lấy một danh sách từ đối tượng bản đồ bằng cách chỉ lặp lại từng mục trong đối tượng và lưu trữ nó trong một biến khác nhau.

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

0

Sử dụng khả năng hiểu danh sách trong python và tiện ích chức năng bản đồ cơ bản, người ta cũng có thể làm điều này:

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


danh sách chi sẽ được chứa, giá trị ASIC của các yếu tố nhất định.
darshan ks
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.