Как можно преобразовать список списков в один плоский список?
У меня есть вложенная структура списков:
[
[1, 2, 3],
[4, 5, 6],
[7],
[8, 9]
]
Какой лучший способ преобразовать это в один плоский список [1, 2, 3, 4, 5, 6, 7, 8, 9]?
Примечание: Если ваш список списков получен из вложенного спискового включения, проблему можно решить проще/прямолинейнее, исправив это включение.
Также обратите внимание: Большинство решений для сглаживания списков обрабатывают только один уровень вложенности. Для полного сглаживания глубоко вложенных структур (рекурсивно) требуются другие подходы.
Чтобы преобразовать список списков в один плоский список, можно использовать несколько методов в зависимости от ваших конкретных потребностей. Для одноуровневой вложенности, как в вашем примере, наиболее эффективным и “питоническим” подходом является использование спискового включения: [x for sublist in nested_list for x in sublist]. Для глубоко вложенных структур потребуются рекурсивные подходы или специализированные библиотеки.
Содержание
- Общие методы для одноуровневого преобразования
- Сравнение производительности методов преобразования
- Рекурсивное преобразование для глубоко вложенных структур
- Использование библиотек для сложного преобразования
- Лучшие практики и рекомендации
Общие методы для одноуровневого преобразования
Списковое включение
Самый эффективный и “питонический” способ преобразования одноуровневого вложенного списка в плоский - использование спискового включения. Этот метод одновременно читабелен и производителен.
nested_list = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
flat_list = [x for sublist in nested_list for x in sublist]
print(flat_list) # Вывод: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Как показано в исследованиях Stack Overflow, это на самом деле самый быстрый метод, результаты бенчмарков показывают 143 мкс на цикл по сравнению с 969 мкс для подхода с sum().
Вложенный цикл for
Традиционный подход с использованием вложенного цикла for более многословный, но очень понятный и читаемый:
nested_list = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
flat_list = []
for sublist in nested_list:
for element in sublist:
flat_list.append(element)
Согласно Python Engineer, этот подход использует цикл for для итерации по основному списку и еще один вложенный цикл for для итерации по каждому элементу подсписков.
Использование itertools.chain
Метод itertools.chain предоставляет эффективный способ преобразования списков путем соединения подсписков:
from itertools import chain
nested_list = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
flat_list = list(chain.from_iterable(nested_list))
В документации Vultr объясняется, что itertools.chain предоставляет метод под названием chain, который может быть полезен, особенно в сочетании с chain.from_iterable для преобразования списков.
Использование функции sum()
Также можно использовать встроенную функцию sum() с пустым списком в качестве начального значения:
nested_list = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
flat_list = sum(nested_list, [])
Однако, как отмечено в бенчмарках Stack Overflow, этот метод значительно медленнее (969 мкс на цикл) по сравнению со списковым включением.
Сравнение производительности методов преобразования
На основе исследований, вот как различные методы сравниваются по производительности:
| Метод | Производительность | Читаемость | Лучше всего подходит для |
|---|---|---|---|
| Списковое включение | Самый быстрый (143 мкс/цикл) | Высокая | Одноуровневая вложенность, общее использование |
| sum() с [] | Медленный (969 мкс/цикл) | Средняя | Простые случаи, избегать для больших списков |
| reduce() с lambda | Очень медленный (1.1 мс/цикл) | Низкая | Устаревший код, избегать в новых проектах |
| itertools.chain() | Быстрый | Средняя | Одноуровневая вложенность, эффективность памяти |
Бенчмарки Stack Overflow ясно показывают, что списковое включение побеждает по производительности, в то время как sum() и reduce() значительно медленнее из-за создания промежуточных списков.
Рекурсивное преобразование для глубоко вложенных структур
При работе со списками произвольной вложенности, такими как [1, [2, [3, 4]], [5, 6]], требуются рекурсивные подходы:
Базовая рекурсивная функция
def flatten_recursive(nested_list):
result = []
for element in nested_list:
if isinstance(element, list):
result.extend(flatten_recursive(element))
else:
result.append(element)
return result
deeply_nested = [1, [2, [3, 4]], [5, 6]]
print(flatten_recursive(deeply_nested)) # [1, 2, 3, 4, 5, 6]
Согласно Finxter, рекурсия - это мощный инструмент для работы с глубоко вложенными списками, и пользовательские рекурсивные функции могут обрабатывать более сложные структуры.
Альтернативная рекурсивная реализация
def flatten_list(nested_list):
if not nested_list:
return []
if isinstance(nested_list[0], list):
return flatten_list(nested_list[0]) + flatten_list(nested_list[1:])
return nested_list[:1] + flatten_list(nested_list[1:])
Как описано в учебнике GeeksforGeeks, этот подход проверяет, является ли первый элемент списком, и рекурсивно обрабатывает как первый элемент (если это список), так и остальную часть списка.
Обработка смешанных типов данных
Для списков, которые могут содержать строки или другие несписковые элементы, которые не должны преобразовываться:
def safe_flatten(nested_list):
result = []
for element in nested_list:
if isinstance(element, list):
result.extend(safe_flatten(element))
elif not isinstance(element, str): # Не преобразовывать строки
result.append(element)
return result
Использование библиотек для сложного преобразования
Библиотека more-itertools
Для сложных сценариев преобразования библиотека more-itertools предоставляет специализированные функции:
from more_itertools import collapse
deeply_nested = [1, [2, [3, 4]], [5, 6], "hello", ["world"]]
flat_list = list(collapse(deeply_nested))
# Управление типами для преобразования
flat_list_no_strings = list(collapse(deeply_nested, base_type=int))
Как упоминается в руководстве Medium, библиотеки вроде more-itertools и их функция collapse особенно полезны для глубоко вложенных структур.
Подход с NumPy
Для числовых данных NumPy предоставляет эффективное преобразование:
import numpy as np
nested_list = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
flat_array = np.array(nested_list).flatten().tolist()
В руководстве Medium также упоминается преобразование в массивы numpy и использование метода flatten() как опции.
Лучшие практики и рекомендации
Выберите подходящий метод для вашего случая использования
- Для одноуровневой вложенности: Используйте списковое включение - оно самое быстрое и читаемое
- Для глубоко вложенных структур: Используйте рекурсивные функции или more-itertools
- Для больших наборов данных: Учитывайте эффективность памяти и используйте генераторы где возможно
- Для смешанных типов данных: Используйте безопасные рекурсивные функции с проверкой типов
Рекомендации по производительности
- Списковые включения обычно самые быстрые для одноуровневого преобразования источник
- Избегайте использования
sum()иreduce()для преобразования, так как они создают промежуточные списки - Для очень больших списков рассмотрите возможность использования генераторов вместо создания полного списка в памяти
Рекомендации по стилю кода
# Лучше всего для одноуровневой вложенности
flat_list = [item for sublist in nested_list for item in sublist]
# Лучше всего для глубокой вложенности с безопасностью типов
def flatten(nested_list, base_type=(int, float, str)):
result = []
for element in nested_list:
if isinstance(element, list):
result.extend(flatten(element, base_type))
elif not isinstance(element, str): # Не преобразовывать строки
result.append(element)
return result
Как отмечено в руководстве CodeRivers, понимание этих методов повышает способность разработчика эффективно манипулировать структурами данных в Python.
Источники
- Stack Overflow - Как сделать плоский список из списка списков?
- GeeksforGeeks - Программа на Python для преобразования вложенного списка с использованием рекурсии
- Python Engineer - Как преобразовать список списков в Python
- Документация Vultr - Программа на Python для преобразования вложенного списка
- Finxter - Преобразование списка списков в Python
- Medium - Как преобразовать список списков с помощью Python: Руководство
- CodeRivers - Преобразование списка в Python: Концепции, методы и лучшие практики
Заключение
Преобразование списков списков - это распространенная задача в Python с несколькими решениями в зависимости от ваших потребностей. Для простых одноуровневых вложенностей списковые включения предлагают наилучшее сочетание производительности и читаемости. Для глубоко вложенных структур рекурсивные функции или специализированные библиотеки вроде more-itertools предоставляют наиболее надежные решения. Всегда учитывайте конкретную структуру ваших данных, требования к производительности и читаемость кода при выборе метода преобразования. Самый важный вывод заключается в том, что списковые включения обычно являются лучшим выбором для одноуровневого преобразования, в то время как рекурсивные подходы необходимы для обработки структур данных с произвольной вложенностью.