На этом шаге мы познакомимся с замечательной возможностью Python: присваиванием срезам. В процессе присваивания
срезам с левой стороны используется нотация среза для модификации подпоследовательности исходной последовательности.
Представьте, что работаете в маленьком интернет-стартапе, отслеживающем, какие браузеры встречаются у его пользователей (Google Chrome, Firefox, Safari). Данные хранятся в БД. Для их анализа вы загружаете собранные данные о браузерах в большой список строковых значений, но из-за ошибки в алгоритме отслеживания каждая вторая строка ошибочна и требует замены на правильную.
Пусть ваш веб-сервер всегда перенаправляет первый веб-запрос пользователя на другой URL (распространенная практика в веб-разработке, известная под кодом HTML 301: перемещено навсегда). Из этого мы делаем вывод, что первое значение для браузера будет равно второму в большинстве случаев, поскольку при ожидании перенаправления браузер пользователя не меняется. Это означает, что можно легко восстановить исходные данные. Фактически нам нужно дублировать каждое второе строковое значение в списке, то есть превратить список ['Firefox', 'corrupted', 'Chrome', 'corrupted'] в список ['Firefox', 'Firefox', 'Chrome', 'Chrome'].
Как сделать это быстро, удобочитаемо и эффективно (желательно в одной строке кода)? Сначала в голову приходит идея создать новый список, пройти в цикле по поврежденному списку и добавить каждое из неиспорченных значений для браузеров в новый список дважды. Но это требует двух списков в коде, каждый из которых может включать миллионы записей. Кроме того, данное решение требует нескольких строк кода, а значит, отрицательно скажется на лаконичности и удобочитаемости исходного кода.
К счастью, вы только что узнали о замечательной возможности Python: присваивании срезам. Оно позволяет выбирать и заменять последовательности элементов, расположенных между индексами i и j, с помощью нотации срезов вида lst[i:j] = [0 0 ...0]. Благодаря тому что срез lst[i:j] стоит с левой стороны операции присваивания (а не с правой, как мы видели раньше), эта возможность и называется присваиванием срезам.
Идея присваивания срезу проста и состоит в замене всех выбранных элементов исходной последовательности слева элементами справа.
Наша цель - заменить каждое второе строковое значение на непосредственно предшествующее ему (пример 2.7).
## Данные visitors = ['Firefox', 'corrupted', 'Chrome', 'corrupted', 'Safari', 'corrupted', 'Safari', 'corrupted', 'Chrome', 'corrupted', 'Firefox', 'corrupted'] ## Однострочник visitors[1::2] = visitors[::2] ## Результат print(visitors)
Какова же будет исправленная последовательность браузеров в результате выполнения этого кода?
Наше однострочное решение заменяет "испорченные" строковые значения на строки с браузерами, которые предшествуют им в списке. Для доступа к испорченным элементам в списке visitors используется нотация присваивания срезам. Мы выделили выбранные элементы в следующем фрагменте кода:
visitors = ['Firefox', 'corrupted', 'Chrome', 'corrupted', 'Safari', 'corrupted', 'Safari', 'corrupted', 'Chrome', 'corrupted', 'Firefox', 'corrupted']
Наш код заменяет эти выделенные элементы срезом справа от операции присваивания. Они выделены в следующем фрагменте кода:
visitors = ['Firefox', 'corrupted', 'Chrome', 'corrupted', 'Safari', 'corrupted', 'Safari', 'corrupted', 'Chrome', 'corrupted', 'Firefox', 'corrupted']
Элементы из первого указанного набора заменяются элементами из второго. Таким образом, итоговый список visitors выглядит так (жирным шрифтом выделены замененные элементы):
print(visitors) # ['Firefox', 'Firefox', 'Chrome', 'Chrome', 'Safari', 'Safari', 'Safari', 'Safari', 'Chrome', 'Chrome', 'Firefox', 'Firefox']
Результат представляет собой исходный список, в котором все строковые значения 'corrupted' заменены предшествующими им строковыми значениями с указанием браузера. Таким образом, мы исправляем испорченный набор данных.
Присваивания срезам - простейший и наиболее эффективный способ решения нашей маленькой задачи. Обратите внимание, что статистика использования браузеров в очищенных данных неискаженная: браузер с долей на рынке 70% в испорченных данных сохранит долю на рынке 70% и в очищенных данных. Очищенные данные можно затем применять для дальнейшего анализа - например, чтобы узнать, лучшие ли покупатели пользователи Safari (в конце концов, они обычно тратят больше денег на аппаратное обеспечение).
Итак, вы освоили простую и лаконичную методику модификации списков программным образом, причем без создания дополнительных объектов.
На следующем шаге мы рассмотрим анализ данных о сердечной деятельности с помощью конкатенации списков.