Отримання карти () для повернення списку в Python 3.x


523

Я намагаюся зіставити список у шістнадцятковий, а потім використати його в іншому місці. У python 2.6 це було просто:

A: Python 2.6:

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

Однак у Python 3.1 вищесказане повертає об’єкт карти.

B: Python 3.1:

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

Як отримати відображений список (як в А вище) на Python 3.x?

Як варіант, чи є кращий спосіб зробити це? Мій початковий об'єкт списку містить близько 45 елементів, і я люблю конвертувати їх у шістнадцятковий.


2
Більш пітонічно використовувати розуміння списку . майже неmap() було видалено з мови, тому що немає ніяких причин використовувати її для розуміння списку чи forциклу.
Борис

Відповіді:


771

Зробити це:

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

У Python 3+ багато процесів, які повторюють ітерабелі, повертають ітераторів. У більшості випадків це закінчує економію пам’яті, і це повинно робити швидше.

Якщо все, що ви збираєтеся зробити, це перебирати цей список, зрештою, не потрібно навіть перетворювати його в список, оскільки ви все одно можете переглядати mapоб'єкт так:

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

15
Звичайно, ви можете також повторити це: (chr (x) для x в [65,66,67,68]). Тут навіть не потрібна карта.
hughdbrown

2
@hughdbrown Аргументом для використання 3.1 mapбуде лінива оцінка при повторенні складної функції, великих наборів даних або потоків.
Ендрю Кітон

18
@Andrew насправді Х'ю використовує розуміння генератора, яке б зробило те саме. Зверніть увагу на дужки, а не на квадратні дужки.
Триптих

5
Альтернативне рішення (швидше і для великих входів), коли значення, як відомо, є ASCII / latin-1, - це робити об'ємні перетворення на шарі C: bytes(sequence_of_ints_in_range_0_to_256).decode('latin-1')що робить strшвидше, уникаючи викликів функції Python для кожного елемента на користь масового перетворення всі елементи, що використовують лише виклики функції С. Ви можете обговорити вищезазначене, listякщо вам справді потрібні listокремі символи, але оскільки strце вже є ітерабельним власними персонажами, єдина причина, яку ви зробите це, якщо вам потрібна зміна.
ShadowRanger

1
list (map (str, [1,2,3])) дає "Помилка в аргументі" для Python 3.4.3 на CentOS 7. Поглиблення списку працює.
Андор

108

Нове та акуратне в Python 3.5:

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

Завдяки додатковим розпакуванням узагальнень

ОНОВЛЕННЯ

Завжди шукаючи більш короткі шляхи, я виявив, що цей також працює:

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

Розпакування працює і в кортежах. Зауважте кому в кінці. Це робить його кортежем з 1 елемента. Тобто це рівнозначно(*map(chr, [66, 53, 0, 94]),)

Це коротше на одну таблицю від версії з дужками списку, але, на мій погляд, краще написати, тому що ви починаєте прямо вперед із зірочкою - синтаксисом розширення, тому я відчуваю, що на увазі це м'якше. :)


11
@Quelklef list()виглядає не так акуратно
Arijoon

5
@Quelklef: Крім того, підхід до розпакування тривіально швидший завдяки тому, що не потрібно шукати listконструктор і не використовувати загальну техніку виклику функцій. Для тривалого введення це не має значення; для короткого - це може змінити велике значення. Використовуючи вищевказаний код із введенням як такий, tupleщоб його не повторно реконструювали, ipythonмікропозначки показують, що list()підхід для обгортання займає приблизно 20% довше, ніж розпакування. Зверніть увагу, ми в абсолютному розумінні говоримо про 150 нс, що тривіально, але ви розумієте.
ShadowRanger

Що сталося зі старим map? Можливо, з новим ім'ям ( lmap?), Якщо новий за замовчуванням має повернути ітератор?
Джорджіо

1
*map()дає помилку синтаксису на Python 3.6: can't use starred expression here. Потрібно помістити його в list:[ *map() ]
ALH

4
@ALH Ви пропустили кому в кінці команди. Легка помилка зробити!
LondonRob

103

Чому ти цього не робиш:

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

Це називається осмисленням списку. Ви можете знайти багато інформації в Google, але ось посилання на документацію Python (2.6) про розуміння списку . Можливо, вас більше зацікавить документування Python 3 .


4
Гмммм. Можливо, там має бути загальна публікація про розуміння списку, генераторів, map (), zip () та багато інших швидкостей ітерації в python.
hughdbrown

46
Я думаю, тому що це більш багатослівний, ви повинні написати додаткову змінну (двічі) ... Якщо операція складніша, і ви закінчите писати лямбда, або вам також потрібно відкинути деякі елементи, я думаю, що розуміння остаточно краще ніж карта + фільтр, але якщо у вас вже є функція, яку ви хочете застосувати, карта є більш короткою.
фортран

1
+1: Легше читати & дозволяє використовувати функції з багатьма параметрами
Le Droid

7
map(chr, [66,53,0,94])безумовно, більш стислий, ніж [chr(x) for x in [66,53,0,94]].
Джорджіо

Швидше за інші відповіді
Евхз

25

Функція карти, що повертається у списку, має перевагу в збереженні набору тексту, особливо під час інтерактивних сесій. Ви можете визначити lmapфункцію (за аналогією python2's imap), яка повертає список:

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

Тоді дзвінок lmapзамість " mapВиклик" зробить цю роботу: lmap(str, x)він коротший на 5 символів (у цьому випадку на 30%), ніж list(map(str, x))і, звичайно, коротший [str(v) for v in x]. Ви також можете створити подібні функції filter.

Був коментар до початкового питання:

Я б запропонував перейменувати в Getting map (), щоб повернути список у Python 3. *, як це стосується всіх версій Python3. Чи є спосіб це зробити? - meawoppl 24 січня о 17:58

Це є можливість зробити це, але це дуже погана ідея. Просто для розваги, ось як ви можете ( але не повинні ) це робити:

__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

Перетворення мого старого коментаря для кращої наочності: Для "кращого способу зробити це" без mapцілковитості, якщо ваші входи, як відомо, порядки ASCII, як правило, набагато швидше конвертувати в bytesта розшифрувати, а-ля bytes(list_of_ordinals).decode('ascii'). Це дає вам strзначення, але якщо вам потрібна можливість зміни listабо подібне, ви можете просто перетворити його (і це все-таки швидше). Наприклад, в ipythonмікропоказів, що перетворюють 45 входів:

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

Якщо ви залишите це як str, це займе ~ 20% часу найшвидших mapрішень; навіть перетворення назад до списку, це все ще менше 40% найшвидшого mapрішення. Масове перетворення через, bytesа bytes.decodeпотім групове перетворення назад, listекономить багато роботи, але, як зазначалося, працює лише в тому випадку, якщо всі ваші входи - це порядки ASCII (або порядкові знаки в одному байті на конкретному кодуванні локального символу, наприклад latin-1).


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

map (func, * iterables) -> об'єкт map Зробіть ітератор, який обчислює функцію, використовуючи аргументи з кожного з ітерабелів. Зупиняється, коли вичерпається найкоротший ітерабельний.

"Зробити ітератор"

означає, що він поверне ітератор.

"що обчислює функцію, використовуючи аргументи з кожного ітерабелу"

означає, що наступна () функція ітератора прийме одне значення кожного ітераберу і передасть кожне з них одному позиційному параметру функції.

Таким чином, ви отримуєте ітератор з функції map () і jsut передаєте його до вбудованої функції list () або використовуєте розуміння списку.


2

У доповненні до вище відповідей в Python 3, ми можемо просто створити listзначення результату з , mapяк

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

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

Ми можемо узагальнити іншим прикладом, коли мене вразило, операції на карті також можна обробляти аналогічно, як і в regexпроблемі, ми можемо записати функцію для отримання listелементів для відображення та отримання результату, встановленого одночасно. Вих.

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 Я вважав, що в Python 2 список повернуто, але в Python 3 повертається лише тип, і я просто намагався дати в тому ж форматі. Якщо ви вважаєте його непотрібним, можливо, такі люди, як я, можуть знайти це корисним, і ось чому я додав.
Harry_pb

2
Коли вже є розуміння списку, функції списку та розпакування відповіді, явний цикл не додає багато IMHO.
miradulo

1

Ви можете спробувати отримати список від об’єкта карти, просто повторивши кожен елемент у об'єкті та зберігаючи його в іншій змінній.

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

0

Використовуючи розуміння списку в програмі утиліти python та basic map, можна також зробити це:

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


Чи буде містити список чі, значення ASIC даних елементів.
darshan ks
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.