Шаг 28.
Однострочники Python.
Трюки Python. Исправление испорченных списков с помощью присваивания срезам

    На этом шаге мы познакомимся с замечательной возможностью 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).


Пример 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 (в конце концов, они обычно тратят больше денег на аппаратное обеспечение).

    Итак, вы освоили простую и лаконичную методику модификации списков программным образом, причем без создания дополнительных объектов.

    На следующем шаге мы рассмотрим анализ данных о сердечной деятельности с помощью конкатенации списков.




Предыдущий шаг Содержание Следующий шаг