Как из вложенного списка сделать один python



Скачай курс
в приложении
Перейти в приложение
Открыть мобильную версию сайта
© 2013 — 2023. Stepik
Наши условия использования и конфиденциальности

Public user contributions licensed under cc-wiki license with attribution required
Вложенные списки Python
Элементами списка Python могут быть списки. В результате получаем вложенные списки или списки списков. Аналог — матрицы второго порядка. Пример списка из двух элементов приведен ниже. Но, каждый из этих элементов тоже список, но уже состоящий из трех элементов.
s = [[1, 2, 3], [4, 5, 6]] print(s)
Доступ к элементам вложенных списков можно получить с помощью индексов. Ниже приведены примеры.
s = [[1, 2, 3], [4, 5, 6]] print(s[0]) print(s[1]) m = s[0] print(m) print(s[0][2]) s[0][1] = 7 print(s) print(m) m[2] = 9 print(s[0]) print(m)
В Python в списках можно использовать отрицательные индексы.
a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]] print(a[0][-2])
Пример перебора всех элементов вложенного списка — используются вложенные циклы. В этом примере также показано, что вложенные в список списки могут быть разной длины.
s = [[1, 2, 3, 4], [5, 6], [7, 8, 9]] for i in range(len(s)): for j in range(len(s[i])): print(s[i][j], end=’ ‘) print()
Следующий пример показывает неявный способ перебора элементов вложенного списка.
a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]] for row in a: for elem in row: print(elem, end=’ ‘) print()
Можно также использовать метод join для перебора.
a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]] for row in a: print(‘ ‘.join([str(elem) for elem in row]))
Дальше показано как можно создавать вложенные списки.
n = 3 m = 4 a = [0] * n for i in range(n): a[i] = [0] * m print(a)
Еще один способ создания вложенных списков: создать пустой список, а затем в него добавлять списки.
n = 3 m = 4 a = [] for i in range(n): a.append([0] * m) print(a)
Также для создания вложенных списков можно воспользоваться генератором списков.
6 способов слияния списка списков
Зашел тут у нас в офисе разговор как наиболее «красиво» и быстро склеить список списков в Питоне. Действительно как?
Даже такую казалось бы тривиальную задачу можно решить несколькими способами, существенно отличающимися по скорости и выразительности.
ВАРИАНТ1
Все знают, что элементы списка можно перебирать в цикле и, то что можно добавлять элементы в конец. Это приводит нас к первому варианту решения:
def listmerge1 ( lstlst ) :
all = [ ]
for lst in lstlst:
for el in lst:
all . append ( el )
return all
Мало того, что функция растянулось аж на 6 строк, так вдобавок она еще и не эффективная.
Попробуем её улучшить в обоих смыслах: скорости и красоты («pythonic way»).
ВАРИАНТ2
Тут мы вспоминаем, что в Питоне есть оператор «+» для строк и получаем:
def listmerge2 ( lstlst ) :
all = [ ]
for lst in lstlst:
all = all +lst
return all
Это самая медленная реализация. Прокол в том что в таком виде оператор «+» в каждом шаге создает новый объект-список, который на следующем шаге выкидывается и т.д.
ВАРИАНТ3
Исправить легко, надо заменить «+» на форму которая не создает новый список, а добавляет к старому. Это оператор «+ #ff7700″>def listmerge3 ( lstlst ) :
all = [ ]
for lst in lstlst:
all . extend ( lst )
return all
Все последующие решения я буду писать через лямбда-выражения, тк они состоят из одного выражения. Имя аргумента сокращено до ll, тк в коде в одну строку это не уменьшает читабельности.
# через анонимную функцию
listmerge= lambda ll : simple-statement
# эквивалентно
def listmerge ( ll ) :
return simple-statement
ВАРИАНТ4
Используя встроенные функции работы со списками, можно переписать вариант2 в стиле функционального программирования:
listmerge4a= lambda ll: reduce ( lambda a,b: a+b, ll, [ ] )
listmerge4b= lambda ll: sum ( ll, [ ] )
Он чуть чуть быстрее, но все еще тормозной по той же причине, что и его итеративный родственник. Здесь «lambda a,b: a+b» — анонимная функция двух аргументов, которая просто возвращает их сумму. Вариант B это просто шорткат, встроенный в Питон для удобста вычисления суммы элементов. Этот вариант самый короткий.
Лично меня не устраивает ни самый короткий (скорость), ни самый быстрый (красота). Попробуем найти компромисс.
ВАРИАНТ5
С помощью списковых выражений:
listmerge5= lambda ll: [ el for lst in ll for el in lst ]
Не сильно длиннее предыдущего, но радикально быстрее. Вариант несомненно красив, хотя вложенные списковые выражения не всегда понятны с первого взгляда.
ВАРИАНТ6
А что если попробовать переписать самый быстрый вариант в функцональном стиле? Легко:
listmerge6= lambda s: reduce ( lambda d,el: d. extend ( el ) or d, s, [ ] )
Заметьте «d.extend(el) or d» нам пришлось добавить оператор «or» тк метод extend возвращает None. По скорости он практически не уступает самому быстрому методу №3 (разница в скорости буквально единицы процентов и на мой взгляд не существенна).
По моему мнению «выбор редакции» стоит присудить варианту №6)
Для замеров скорости маленьких кусков кода в Питоне есть библиотека timeit. Вот пример кода, тестирующего варианты 3, 5 и 6 (самые быстрые и красивые).
variants = <
‘Reduce’ :
‘listmerge=lambda s: reduce(lambda d,el: d.extend(el) or d, s, [])’ ,
‘Iterate’ :
«»»
def listmerge(lstlst):
all=[]
for lst in lstlst:
all.extend(lst)
return all
«»» ,
‘Comprehension’ :
‘listmerge=lambda ll: [x for lst in ll for x in lst]’ ,
>
initstr= ‘lstlst=[range(i) for i in range(1000)] \n gc.enable()’
def test ( variants, initstr,n= 100 ) :
print «Test repeats n #483d8b»>» times \n INITSTR:» ,initstr, » \n \n »
for k,v in variants. iteritems ( ) :
print k, » — » , timeit . Timer ( «listmerge(lstlst)» , initstr+ » \n » +v ) . timeit ( n )
print
test ( variants,initstr, 100 )
Пример запуска теста времени. Видно что разница скорости между итеративным и функциональным вариантом исчезающе мала. Вариант на списковых выражениях заметно медленней (тут на погрешности не спишешь), но и размер наших списков огромен, для некритичных к скорости приложений он тоже имеет право на жизнь.
Test repeats n = 100 times
INITSTR: lstlst=[range(i) for i in range(1000)]
gc.enable()
Iterate — 1.56133103371
Reduce — 1.57647109032
Comprehension — 7.5749669075
ДОМАШНЕЕ ЗАДАНИЕ
Предлагаю решить/обсудить более сложную задачу развертывание вложенных списков в линейный.
Пример:
# Исходный список:
[ 7 , [ [ [ [ 2 ] ] ] , [ [ [ ] ] , [ 4 ] ] , [ 4 , 5 , [ 6 , 7 ] ] ] , 8 ]
# Результат:
[ 7 , 2 , 4 , 4 , 5 , 6 , 7 , 8 ]
UPD2:
ВАРИАНТ 6Б (от анонимного комментатора в ЖЖ)
Объединить вложенные списки и числа в один список Python
Решил пройти задание на CheckiO, где требуется объединить вложенные списки и числа в один список, например: ([-1, [1, [-2], 1], -1]) == [-1, 1, -2, 1, -1] ([1, [2, 2, 2], 4]) == [1, 2, 2, 2, 4] Кто подскажет, в чём ошибка и как её исправить?
from itertools import chain def flat_list(array): lst_one = [] lst_two = [] for i in array: if isinstance(i, list): lst_one.append(i) if isinstance(i, int): lst_two.append(i) combined = chain(lst_one, lst_two) return list(combined)
Отслеживать
задан 17 мар 2022 в 19:12
9 2 2 бронзовых знака
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Наверное самым логичным решением здесь будет рекурсивная функция.
array_to_parse_1 = ([-1, [1, [-2], 1], -1]) array_to_parse_2 = ([1, [2, 2, 2], 4]) def parse_list(input_array): result_array = [] for array_item in input_array: if isinstance(array_item, list) or isinstance(array_item, tuple): result_array.extend(parse_list(array_item)) else: result_array.append(array_item) return result_array print(parse_list(array_to_parse_1)) print(parse_list(array_to_parse_2))
Отслеживать
ответ дан 17 мар 2022 в 20:27
Дмитрий Игоревич Дмитрий Игоревич
122 3 3 бронзовых знака
Ошибка в том, что по этому условию if isinstance(i, list) вы добавляете в список вложенные списки, а chain сцепляет эти списки с числами. Исправить, как уже сказали, можно использовав рекурсию. Есть еще вариант с генератором, например такой генератор справляется со всеми типами (кроме строк):
def flat_list(array): for i in array: if hasattr(i, '__iter__'): yield from flat_list(i) else: yield i l = [-1, [1, [-2], 1], -1, (3, -3), , [range(8,10), [11, 12, ]]] print([*flat_list(l)]) #------^-распаковка ''' [-1, 1, -2, 1, -1, 3, -3, 4, 6, 8, 9, 11, 12, 13, 14]
Отслеживать
ответ дан 18 мар 2022 в 7:35
5,635 1 1 золотой знак 7 7 серебряных знаков 17 17 бронзовых знаков
- python
- list
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.11.15.1019
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.