Преобразование итераций строк и чисел с помощью map()

Вторая часть статьи «Python’s map(): Processing Iterables Without a Loop», перевод которой выполнил и опубликовал сайт webdevblog.ru. В первой части мы познакомились с map(). Здесь рассмотрим следующие темы:

Преобразование итераций строк с помощью map()

Когда вы работаете с итерациями строковых объектов, вам может быть интересно преобразовать все объекты с помощью какой-либо функции преобразования. В таких ситуациях вам может помочь map(). В следующих разделах вы познакомитесь с некоторыми примерами того, как использовать map() для преобразования итераций строковых объектов.

Использование методов str

Довольно распространенный подход к манипуляциям со строками — использование некоторых методов класса str для преобразования заданной строки в новую строку. Если вы имеете дело с итерациями строк и вам нужно применить одно и то же преобразование к каждой строке, вы можете использовать map() вместе с различными строковыми методами:

>>> string_it = ["processing", "strings", "with", "map"]
>>> list(map(str.capitalize, string_it))
['Processing', 'Strings', 'With', 'Map']

>>> list(map(str.upper, string_it))
['PROCESSING', 'STRINGS', 'WITH', 'MAP']

>>> list(map(str.lower, string_it))
['processing', 'strings', 'with', 'map']

Есть несколько преобразований, которые вы можете выполнить для каждого элемента в string_it, используя методы map() и string. В большинстве случаев вы будете использовать методы, которые не принимают дополнительных аргументов, например str.capitalize()str.lower()str.swapcase()str.title() и str.upper().

Вы также можете использовать некоторые методы, которые принимают дополнительные аргументы со значениями по умолчанию, например str.strip(), которая принимает необязательный аргумент char, который по умолчанию удаляет пробелы:

>>> with_spaces = ["processing ", "  strings", "with   ", " map   "]

>>> list(map(str.strip, with_spaces))
['processing', 'strings', 'with', 'map']

Когда вы используете str.strip() таким образом, вы полагаетесь на значение по умолчанию для char. В этом случае вы используете map(), чтобы удалить все пробелы в элементах with_spaces.

Примечание. Если вам нужно предоставить аргументы, а не полагаться на значение по умолчанию, вы можете использовать лямбда-функцию.

Вот пример, в котором для удаления точек используется str.strip(), а не пробелы по умолчанию:

>>> with_dots = ["processing..", "...strings", "with....", "..map.."]

>>> list(map(lambda s: s.strip("."), with_dots))
['processing', 'strings', 'with', 'map']

Лямбда-функция вызывает .strip() для строкового объекта s и удаляет все начальные и конечные точки.

Этот метод может быть удобен, когда, например, вы обрабатываете текстовые файлы, в которых строки могут иметь завершающие пробелы (или другие символы), и вам необходимо их удалить. Если это так, то вам необходимо учитывать, что использование str.strip() без специального символа также удалит символ новой строки.

Удаление знаков препинания

Когда дело доходит до обработки текста, вам иногда нужно удалить знаки препинания, которые остаются после того, как вы разбили текст на слова. Чтобы справиться с этой проблемой, вы можете создать настраиваемую функцию, которая удаляет знаки препинания из одного слова, используя регулярное выражение, которое соответствует наиболее распространенным знакам препинания.

Вот возможная реализация этой функции с помощью sub(), которая представляет собой функцию регулярного выражения, которая находится в модуле re в стандартной библиотеке Python:

>>> import re

>>> def remove_punctuation(word):
...        return re.sub(r'[!?.:;,"()-]', "", word)

>>> remove_punctuation("...Python!")
'Python'

Внутри remove_punctuation() вы используете шаблон регулярного выражения, который соответствует наиболее распространенным знакам препинания, которые вы найдете в любом тексте, написанном на английском языке. Вызов re.sub() заменяет совпадающие знаки препинания пустой строкой («») и возвращает очищенное слово.

Имея функцию преобразования, вы можете использовать map() для запуска преобразования для каждого слова в вашем тексте. Вот как это работает:

>>> text = """Some people, when confronted with a problem, think
... "I know, I'll use regular expressions."
... Now they have two problems. Jamie Zawinski"""

>>> words = text.split()
>>> words
['Some', 'people,', 'when', 'confronted', 'with', 'a', 'problem,', 'think'
, '"I', 'know,', "I'll", 'use', 'regular', 'expressions."', 'Now', 'they',
 'have', 'two', 'problems.', 'Jamie', 'Zawinski']

>>> list(map(remove_punctuation, words))
['Some', 'people', 'when', 'confronted', 'with', 'a', 'problem', 'think',
'I', 'know', "I'll", 'use', 'regular', 'expressions', 'Now', 'they', 'have
', 'two', 'problems', 'Jamie', 'Zawinski']

В этом фрагменте текста некоторые слова содержат знаки препинания. Например, у вас есть «people,» вместо «people», «problem,» вместо «problem» и так далее. Вызов map() применяет remove_punctuation() к каждому слову и удаляет все знаки препинания. Итак, во втором списке вы вычистили слова.

Обратите внимание, что апостроф (‘) отсутствует в вашем регулярном выражении, потому что вы хотите сохранить сокращения, такие как  I'll, такими, какие они есть.

[python_ad_block]

Реализация алгоритма шифрования Цезаря

Юлий Цезарь, римский государственный деятель, использовал для защиты сообщений, которые он отправлял своим генералам шифр. Шифр Цезаря сдвигает каждую букву на количество букв. Например, если сдвинуть букву а на три, получится буква d и так далее.

Если сдвиг выходит за пределы конца алфавита, вам просто нужно вернуться к началу алфавита. В случае поворота на три x станет a. Вот как будет выглядеть алфавит после поворота:

  • Оригинальный алфавит: abcdefghijklmnopqrstuvwxyz
  • Алфавит повернут на три: defghijklmnopqrstuvwxyzabc

Следующий код реализует функцию rotate_chr(), которая принимает символ и поворачивает его на три. rotate_chr() вернет повернутый символ. Вот код:

def rotate_chr(c):
    rot_by = 3
    c = c.lower()
    alphabet = "abcdefghijklmnopqrstuvwxyz"
  
    if c not in alphabet:
        return c
    rotated_pos = ord(c) + rot_by
     
    if rotated_pos <= ord(alphabet[-1]):
        return chr(rotated_pos)
     
    return chr(rotated_pos - len(alphabet))

Внутри rotate_chr() вы сначала проверяете, находится ли символ в алфавите. Если нет, то вы возвращаете тот же символ. Это позволяет сохранить знаки препинания и другие необычные символы. В строке 8 вы вычисляете новую повернутую позицию символа в алфавите. Для этого вы используете встроенную функцию ord().

ord() принимает символ Юникода и возвращает целое число, представляющее кодовую точку Юникода входного символа. Например, ord(«a») возвращает 97, а ord(«b») возвращает 98:

>>> ord("a")
97
>>> ord("b")
98

ord() принимает символ в качестве аргумента и возвращает кодовую точку Unicode входного символа.

Если вы добавите это целое число к целевому числу rot_by, вы получите повернутую позицию новой буквы в алфавите. В этом примере rot_by равно 3. Итак, буква «a», повернутая на три, станет буквой в позиции 100, то есть буквой «d». Буква «b», повернутая на три, станет буквой в позиции 101, то есть буквой «е», и так далее.

Если новая позиция буквы не выходит за пределы позиции последней буквы (alphabet[-1]), то вы возвращаете букву в этой новой позиции. Для этого вы используете встроенную функцию chr().

chr() является обратным к ord(). Он принимает целое число, представляющее кодовую точку Unicode символа Unicode, и возвращает символ в этой позиции. Например, chr(97) вернет ‘a‘, а chr(98) вернет ‘b‘:

>>> chr(97)
'a'
>>> chr(98)
'b'

chr() принимает целое число, представляющее кодовую точку Unicode символа, и возвращает соответствующий символ.

Наконец, если новая повернутая позиция находится за пределами позиции последней буквы (alphabet[-1]), вам нужно повернуть обратно в начало алфавита. Для этого вам нужно вычесть длину алфавита из повернутой позиции (rotated_pos — len (alphabet)), а затем вернуть букву в этой новой позиции с помощью chr().

Используя rotate_chr() в качестве функции преобразования, вы можете использовать map() для шифрования любого текста с помощью алгоритма шифрования Цезаря. Вот пример, в котором str.join() используется для объединения строки:

>>> "".join(map(rotate_chr, "My secret message goes here."))
'pb vhfuhw phvvdjh jrhv khuh.'

Строки также являются итерируемыми в Python. Итак, вызов map() применяет rotate_chr() к каждому символу исходной входной строки. В этом случае «M» становится «p», «y» становится «b» и так далее. Наконец, вызов str.join() объединяет каждый повернутый символ в окончательное зашифрованное сообщение.

Преобразование итераций чисел с помощью map()

map() также имеет большой потенциал, когда дело доходит до обработки и преобразования итераций числовых значений. Вы можете выполнять широкий спектр математических и арифметических операций, преобразовывать строковые значения в числа с плавающей запятой или целые числа и т. д.

В следующих разделах вы рассмотрите несколько примеров того, как использовать map() для обработки и преобразования итераций чисел.

Использование математических операций

Типичным примером использования математических операций для преобразования итерации числовых значений является использование оператора возведения в степень (**). В следующем примере вы кодируете функцию преобразования, которая принимает число и возвращает число в квадрате и кубе:

>>> def powers(x):
...     return x ** 2, x ** 3
...

>>> numbers = [1, 2, 3, 4]

>>> list(map(powers, numbers))
[(1, 1), (4, 8), (9, 27), (16, 64)]

powers() принимает число x и возвращает его квадрат и куб. Поскольку Python обрабатывает несколько возвращаемых значений как кортежи, каждый вызов powers() возвращает кортеж с двумя значениями. Когда вы вызываете map() с powers() в качестве аргумента, вы получаете список кортежей, содержащий квадрат и куб каждого числа во входном итеративном элементе.

Существует множество математических преобразований, которые вы можете выполнить с помощью map(). Вы можете добавлять константы и вычитать их из каждого значения. Вы также можете использовать некоторые функции из математического модуля, такие как sqrt()factorial()sin()cos() и т. д. Вот пример использования factorial():

>>> import math

>>> numbers = [1, 2, 3, 4, 5, 6, 7]

>>> list(map(math.factorial, numbers))
[1, 2, 6, 24, 120, 720, 5040]

В этом случае вы преобразуете числа в новый список, содержащий факториал каждого числа в исходном списке.

Вы можете выполнять широкий спектр математических преобразований итерации чисел с помощью map(). Насколько далеко вы углубитесь в эту тему, будет зависеть от ваших потребностей и вашего воображения. Подумайте об этом и напишите свои собственные примеры!

Преобразование температур

Другой вариант использования map() — преобразование единиц измерения. Предположим, у вас есть список температур, измеренных в градусах Цельсия или Фаренгейта, и вам нужно преобразовать их в соответствующие температуры в градусах Фаренгейта или Цельсия.

Для выполнения этой задачи вы можете закодировать две функции преобразования:

def to_fahrenheit(c):
    return 9 / 5 * c + 32

def to_celsius(f):
    return (f - 32) * 5 / 9

to_fahrenheit() измеренные температуры в градусах Цельсия и преобразует их в градусы Фаренгейта. Точно так же to_celsius() принимает температуру в градусах Фаренгейта и преобразует в градусы Цельсия.

Эти функции будут вашими функциями преобразования. Вы можете использовать их с map() для преобразования повторяемых измерений температуры в градусы Фаренгейта и Цельсия соответственно:

>>> celsius_temps = [100, 40, 80]
>>> # Convert to Fahrenheit
>>> list(map(to_fahrenheit, celsius_temps))
[212.0, 104.0, 176.0]

>>> fahr_temps = [212, 104, 176]
>>> # Convert to Celsius
>>> list(map(to_celsius, fahr_temps))
[100.0, 40.0, 80.0]

Если вы вызовете map() с to_fahrenheit() и celsius_temps, то получите список мер температуры в градусах Фаренгейта. Если вы вызовете map() с to_celsius() и fahr_temps, вы получите список измерений температуры в градусах Цельсия.

Чтобы расширить этот пример и охватить любые другие виды преобразования единиц, вам просто нужно закодировать соответствующую функцию преобразования.

Преобразование строк в числа

При работе с числовыми данными вы, вероятно, столкнетесь с ситуациями, когда все ваши данные являются строковыми значениями. Для дальнейших вычислений вам нужно будет преобразовать строковые значения в числовые значения. map() тоже может помочь в этих ситуациях.

Если вы уверены, что ваши данные чистые и не содержат неправильных значений, вы можете использовать float() или int() в соответствии с вашими потребностями. Вот несколько примеров:

>>> # Convert to floating-point
>>> list(map(float, ["12.3", "3.3", "-15.2"]))
[12.3, 3.3, -15.2]

>>> # Convert to integer
>>> list(map(int, ["12", "3", "-15"]))
[12, 3, -15]

В первом примере вы используете float() с map() для преобразования всех значений из строковых значений в значения с плавающей запятой. Во втором случае вы используете int() для преобразования строки в целое число. Обратите внимание: если одно из значений не является допустимым числом, вы получите ошибку ValueError..

Если вы не уверены, что ваши данные чистые, вы можете использовать более сложную функцию преобразования, например следующую:

>>> def to_float(number):
...     try:
...         return float(number.replace(",", "."))
...     except ValueError:
...         return float("nan")
...

>>> list(map(to_float, ["12.3", "3,3", "-15.2", "One"]))
[12.3, 3.3, -15.2, nan]

Внутри to_float() используется оператор try, который улавливает ValueError, если float() не работает при преобразовании числа. Если ошибки не возникает, функция возвращает число, преобразованное в допустимое число с плавающей запятой. В противном случае вы получите значение nan (не число), которое представляет собой специальное значение с плавающей запятой, которое вы можете использовать для представления значений, которые не являются допустимыми числами, как и «One» в приведенном выше примере.

Вы можете настроить to_float() в соответствии с вашими потребностями. Например, вы можете заменить оператор return float («nan») на оператор return 0.0 и так далее.

Третья (заключительная) часть статьи.