Как объединить вложенные списки в python
Перейти к содержимому

Как объединить вложенные списки в python

  • автор:

Способы слияния списков в Python

Способы слияния списков в Python

Доброго времени суток! В этой статье мы рассмотрим разные способы объединения списков в Python.

Умение работать со списками Python — очень важный навык. Списки в Python являются изменяемыми объектами. Они также могут содержать повторяющиеся значения, которые по-разному упорядочены.

Итак, перейдем непосредственно к рассмотрению примеров.

Самый простой способ объединить списки Python — это использовать либо распаковку списка, либо простой оператор +.

Давайте сначала рассмотрим использование оператора +, поскольку он намного проще и понятнее:

# способ №1 — оператор +

items1 = [‘сайт’, ‘мой’, ‘работает’, ‘нормально’]
items2 = [‘что’, ‘такое’, ‘python’]
items3 = items1 + items2

Здесь мы видим, что когда мы распечатываем третий список, он содержит значения из первого и второго.

Аналогично, мы можем создать новый список, распаковав все элементы из списков, которые хотим объединить. Используя оператор *, мы можем получить доступ ко всем элементам в обоих списках и распаковать их в третий.

Давайте посмотрим, как это будет выглядеть:

# способ №2 — распаковка списков

items1 = [‘сайт’, ‘мой’, ‘работает’, ‘нормально’]
items2 = [‘что’, ‘такое’, ‘python’]
items3 = [*items1, *items2]
print(items3)

Объединение списков Python с использованием Zip

Функция zip последовательно перебирает несколько элементов, позволяя нам получать доступ к элементам по порядку.

Давайте посмотрим, как мы можем использовать функцию zip() для объединения списков в Python поочередно:

# способ №3 — использование функции zip

items1 = [‘сайт’, ‘мой’, ‘работает’, ‘нормально’]
items2 = [‘что’, ‘такое’, ‘python’]

items3 = [item for sublist in zip(items1, items2) for item in sublist]
print(items3)

Функция zip() создает объект zip, который технически является объектом генератора. Когда мы превращаем его обратно в список, мы получаем доступ ко всем элементам в генераторе. Из-за этого мы можем использовать функцию для объединения двух списков Python в последовательном порядке.

Объединение списков без дубликатов

В Python есть структура данных set, которая в чем-то похожа на список, но не может содержать повторяющихся элементов. Мы можем использовать set для удаления любых дубликатов из списка, преобразовав список в set.

Давайте посмотрим, как мы можем объединить списки и удалить все в них дубликаты, используя set:

# способ №4 — слияние списков с удалением дубликатов

list1 = [1, 2, 3, 4]
list2 = [4, 5, 6, 7]
list3 = list(set(list1 + list2))

Что мы здесь сделали:

  1. Мы объединили списки с помощью оператора +,
  2. Затем мы преобразовали этот список в set для удаления дубликатов
  3. Затем мы преобразовали набор обратно в список
Объединение списков в цикле For

Хотя это не тот подход, который необходим в большинстве случаев, но он гибче с точки зрения того, какие элементы включать в итоговый список.

Например, используя цикл for, вы можете пропустить определенные элементы, которые не удовлетворяют определенному условию.

# способ №5 — использование цикла for

list1 = [‘сайт’, ‘мой’, ‘работает’, ‘нормально’]
list2 = [‘что’, ‘такое’, ‘python’]

# вставка значений из первого списка во второй
for item in list2:
list1.append(item)

# слияние по условию — если длина строки больше трех символов
list1 = [‘сайт’, ‘мой’, ‘работает’, ‘нормально’]
list2 = [‘что’, ‘такое’, ‘python’]

for item in list2:
if len(item) > 3:
list1.append(item)

то мы сделали здесь в обоих примерах:

  1. Мы прошлись по нашему второму списку, добавив каждый элемент из второго списка к первому списку — первый вариант
  2. Второй вариант — то же самое, но с условием:
  3. Если условие выполнено, то мы добавляем элемент в список.
  4. Если это не так, то элемент пропускается.
Объединение списков с помощью спискового включения (list comprehension)

Давайте посмотрим, как это выглядит:

# способ №6 — списковое включение (List Comprehension)

list1 = [‘сайт’, ‘мой’, ‘работает’, ‘нормально’]
list2 = [‘что’, ‘такое’, ‘python’]

[list1.append(item) for item in list2]

Объединение списков по общим элементам

Иногда возникает потребность — объединить только общие элементы между двумя списками Python, что означает пересечение между двумя списками.

Давайте посмотрим, как объединять списки только с общими элементами:

# способ №7 — слияние списков только по общим элементам

list1 = [1, 2, 3, 4]
list2 = [3, 4, 5, 6]
list3 = list(set(list1).intersection(set(list2)))

Давайте рассмотрим, что мы здесь сделали:

  1. Оба списка преобразуются в set
  2. Первый набор использует метод .intersection() в который передается набор из второго списка
  3. Окончательный набор возвращается в виде списка

Таким образом, из этой статьи мы рассмотрели разные способы объединения списков в Python.

Создано 17.03.2022 13:29:19

  • Михаил Русаков
  • Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!

    Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
    Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.

    Если Вы не хотите пропустить новые материалы на сайте,
    то Вы можете подписаться на обновления: Подписаться на обновления

    Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

    Порекомендуйте эту статью друзьям:

    Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

    1. Кнопка:
      Она выглядит вот так:
    2. Текстовая ссылка:
      Она выглядит вот так: Как создать свой сайт
    3. BB-код ссылки для форумов (например, можете поставить её в подписи):

    Комментарии ( 0 ):

    Для добавления комментариев надо войти в систему.
    Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.

    Copyright © 2010-2024 Русаков Михаил Юрьевич. Все права защищены.

    Многомерные списки

    Часто в задачах приходится хранить прямоугольные таблицы с данными. Такие таблицы называются матрицами или двумерными массивами. В языке программирования Питон таблицу можно представить в виде списка строк, каждый элемент которого является в свою очередь списком, например, чисел. Например, создать числовую таблицу из двух строк и трех столбцов можно так:

    a = [[1, 2, 3], [4, 5, 6]]

    Здесь первая строка списка a[0] является списком из чисел [1, 2, 3] . То есть a[0][0] == 1 , значение a[0][1] == 2 , a[0][2] == 3 , a[1][0] == 4 , a[1][1] == 5 , a[1][2] == 6 .

    Для обработки и вывода списка как правило используется два вложенных цикла. Первый цикл по номеру строки, второй цикл по элементам внутри строки. Например, вывести двумерный числовой список на экран построчно, разделяя числа пробелами внутри одной строки, можно так:

    for i in range(len(a)): for j in range(len(a[i])): print(a[i][j], end=' ') print()

    То же самое, но циклы не по индексу, а по значениям списка:

    for row in a: for elem in row: print(elem, end=' ') print()

    Естественно для вывода одной строки можно воспользоваться методом join :

    for row in a: print(' '.join(map(str, row)))

    Используем два вложенных цикла для подсчета суммы всех чисел в списке:

    s = 0 for i in range(len(a)): for j in range(len(a[i])): s += a[i][j]

    Или то же самое с циклом не по индексу, а по значениям строк:

    s = 0 for row in a: for elem in row: s += elem

    Создание списка

    Пусть даны два числа: количество строк n и количество столбцов m . Необходимо создать список размером n × m , заполненный нулями.

    Очевидное решение оказывается неверным:

    a = [[0] * m] * n

    В этом легко убедиться, если присвоить элементу a[0][0] значение 1 , а потом вывести значение другого элемента a[1][0] — оно тоже будет равно 1! Дело в том, что [0] * m возвращает ccылку на список из m нулей. Но последующее повторение этого элемента создает список из n элементов, которые являются ссылкой на один и тот же список (точно так же, как выполнение операции b = a для списков не создает новый список), поэтому все строки результирующего списка на самом деле являются одной и той же строкой.

    Таким образом, двумерный список нельзя создавать при помощи операции повторения одной строки. Что же делать?

    Первый способ: сначала создадим список из n элементов (для начала просто из n нулей). Затем сделаем каждый элемент списка ссылкой на другой одномерный список из m элементов:

    a = [0] * n for i in range(n): a[i] = [0] * m

    Другой (но похожий) способ: создать пустой список, потом n раз добавить в него новый элемент, являющийся списком-строкой:

    a = [] for i in range(n): a.append([0] * m)

    Но еще проще воспользоваться генератором: создать список из n элементов, каждый из которых будет списком, состоящих из m нулей:

    a = [[0] * m for i in range(n)]

    В этом случае каждый элемент создается независимо от остальных (заново конструируется список [0] * m для заполнения очередного элемента списка), а не копируются ссылки на один и тот же список.

    Ввод списка

    Пусть программа получает на вход двумерный массив, в виде n строк, каждая из которых содержит m чисел, разделенных пробелами. Как их считать? Например, так:

    a = [] for i in range(n): a.append(list(map(int, input().split())))

    Или, без использования сложных вложенных вызовов функций:

    a = [] for i in range(n): row = input().split() for i in range(len(row)): row[i] = int(row[i]) a.append(row)

    Можно сделать то же самое и при помощи генератора:

    a = [list(map(int, input().split())) for i in range(n)]

    Сложный пример обработки массива

    Пусть дан квадратный массив из n строк и n столбцов. Необходимо элементам, находящимся на главной диагонали, проходящей из левого верхнего угла в правый нижний (то есть тем элементам a[i][j] , для которых i == j ) присвоить значение 1 , элементам, находящимся выше главной диагонали – значение 0, элементам, находящимся ниже главной диагонали – значение 2. То есть получить такой массив (пример для n==4 ):

    1 0 0 0 2 1 0 0 2 2 1 0 2 2 2 1

    Рассмотрим несколько способов решения этой задачи. Элементы, которые лежат выше главной диагонали – это элементы a[i][j] , для которых i < j , а для элементов ниже главной диагонали i >j . Таким образом, мы можем сравнивать значения i и j и по ним определять значение a[i][j] . Получаем следующий алгоритм:

    for i in range(n): for j in range(n): if i < j: a[i][j] = 0 elif i >j: a[i][j] = 2 else: a[i][j] = 1

    Данный алгоритм плох, поскольку выполняет одну или две инструкции if для обработки каждого элемента. Если мы усложним алгоритм, то мы сможем обойтись вообще без условных инструкций.

    Сначала заполним главную диагональ, для чего нам понадобится один цикл:

    for i in range(n): a[i][i] = 1

    Затем заполним значением 0 все элементы выше главной диагонали, для чего нам понадобится в каждой из строк с номером i присвоить значение элементам a[i][j] для j = i+1 , . n-1 . Здесь нам понадобятся вложенные циклы:

    for i in range(n): for j in range(i + 1, n): a[i][j] = 0

    Аналогично присваиваем значение 2 элементам a[i][j] для j = 0 , . i-1 :

    for i in range(n): for j in range(0, i): a[i][j] = 2

    Можно также внешние циклы объединить в один и получить еще одно, более компактное решение:

    for i in range(n): for j in range(0, i): a[i][j] = 2 a[i][i] = 1 for j in range(i + 1, n): a[i][j] = 0

    А вот такое решение использует операцию повторения списков для построения очередной строки списка. i -я строка списка состоит из i чисел 2 , затем идет одно число 1 , затем идет n-i-1 число 0 :

    for i in range(n): a[i] = [2] * i + [1] + [0] * (n - i - 1)

    А можно заменить цикл на генератор:

    a = [[2] * i + [1] + [0] * (n - i - 1) for i in range(n)]

    Форматирование вывода

    В некоторых заданиях этого листка требуется выводить элементы списка аккуратными столбцами, выравнивая числа по правому краю с фиксированной шириной столбца. Это можно сделать разными способами, один из способов: использование метода rjust .

    rjust — метод объекта типа str , принимающий два параметра: длину новой строки (ширина поля вывода) и символ-заполнитель: rjust(n, ch) . Например, s.rjust(10, ‘.’) . Метод возвращает новую строку, длина которой равна n символов, исходная строка находится в конце результата (то есть исходная строка “выравнивается” по правому краю), лишние позиции заполняются символом ch. Если опустить ch, то в качестве символа-заполнителя используется пробел. Если длина исходной строки была больше n, то возвращается исходная строка без изменений (строка не обрезается).

    Аналогично есть методы ljust , выравнивающий строку по левому краю и center , выравнивающий строку по центру результата.

    Объединить вложенные списки и числа в один список 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,645 1 1 золотой знак 7 7 серебряных знаков 17 17 бронзовых знаков

    • python
    • list
      Важное на Мете
    Похожие

    Подписаться на ленту

    Лента вопроса

    Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

    Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.3.8.5973

    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Б (от анонимного комментатора в ЖЖ)

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

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