Перейти к содержимому

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

  • автор:

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

Скачай курс
в приложении

Перейти в приложение
Открыть мобильную версию сайта

© 2013 — 2023. Stepik

Наши условия использования и конфиденциальности

Get it on Google Play

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.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *