Как объединить списки в Python
В этом руководстве мы представим различные методы объединения списков в Python. Списки служат для хранения однородных элементов и выполнения над ними манипуляций.
В общем, конкатенация – это процесс соединения элементов определенной структуры данных сквозным способом.
Ниже приведены 6 способов объединения списков в Python.
- оператор конкатенации (+);
- метод Naive;
- List Comprehension;
- метод extension()
- оператор ‘*’;
- метод itertools.chain().
1. Оператор (+) для конкатенации списков
Оператор «+» можно использовать для объединения двух списков. Он добавляет один список в конец другого списка и дает новый список в качестве вывода.
2. Метод Naive
В методе Naive цикл for используется для обхода второго списка. После этого элементы из второго списка добавляются к первому списку. Первый список является объединением первого и второго списков.
3. Concatenated list для объединения списков
Concatenated list в Python – это альтернативный метод объединения двух списков в Python. Понимание списка – это в основном процесс построения и генерации списка элементов на основе существующего списка.
Он использует цикл for для обработки и обхода списка поэлементно. Приведенный ниже встроенный цикл for эквивалентен вложенному циклу for.
4. Метод extend()
Метод extend() можно использовать для объединения двух списков в Python. Функция extend() выполняет итерацию по переданному параметру и добавляет элемент в список, тем самым расширяя список линейным образом.
Все элементы list2 добавляются к list1, и, таким образом, list1 обновляется и выводится.
5. Оператор ‘*’
Оператор Python ‘*’ можно использовать для простого объединения двух списков. Оператор ‘*’ в Python в основном распаковывает коллекцию элементов по аргументам индекса.
Например: рассмотрим список my_list = [1, 2, 3, 4].
Оператор * my_list заменит список его элементами в позициях индекса. Таким образом, он распаковывает элементы списков.
В приведенном выше фрагменте кода инструкция res = [* list1, * list2] заменяет list1 и list2 элементами в заданном порядке, то есть элементами list1 после элементов list2. Это выполняет конкатенацию и приводит к выводу ниже.
6. Метод Python itertools.chain()
Функция itertools.chain() модулей itertools также может использоваться для объединения списков в Python. Функция принимает в качестве параметров различные итерации, такие как списки, строки, кортежи и т.д., и выдает их последовательность в качестве вывода.
В результате получается линейная последовательность. Тип данных элементов не влияет на работу метода chain().
Создание списков в Python. Объединение списков в Python. Функция list() в Python
Популярность Python обуславливается его относительной простотой и широкими функциональными возможностями. Среди них — успешная работа со структурами данных — это списки, кортежи, словари и множества. В нашей сегодняшней статье мы разберёмся со списками, поговорим про добавление и поиск элементов, а напоследок подробно расскажем об особенностях сортировки в Python.
Что такое список в Python?
Список (list) представляет собой структуру данных, предназначенную для хранения объектов. При этом не стоит путать список с массивом.
Некоторые особенности списка в Python: — в списке можно хранить элементы разных типов; — размер списка можно изменять.
Как хранятся списки в памяти?
Во время создания списка в Python происходит резервирование пустой области в памяти. Условно можно сказать, что это некий контейнер, где содержатся ссылки на другие элементы данных. Однако в отличие от таких данных, как строка либо число, содержимое контейнера списка может меняться.
Чтобы лучше представлять вышеописанный процесс, посмотрим на картинку. Мы увидим список, который содержит ссылки на объекты 1 и 2. При этом после выполнения операции a[1] = 3, вторая ссылка станет указывать на объект № 3 (в Питоне элементы списка нумеруются, начиная с нуля).
Создание, удаление и изменение списков, а также работа с его элементами
Создать список в Python можно следующим способом:
Кроме того, возможно создание списка с заранее известным набором данных:
Если список уже есть и нужно создать копию, это тоже не проблема:
Обратите внимание, что если вы делаете простое присваивание списков друг другу, то переменной (в нашем примере это b) присваивается ссылка на тот же самый элемент данных в памяти, как и в списке a (не на копию списка a). Таким образом, если захотите изменить список a, b тоже будет меняться.
Если нужно добавить элемент в список, используем метод append() :
А если требуется удалить элемент из списка в том случае, когда его значение известно, рекомендуется применение метода remove(x) , который удалит первую ссылку на этот элемент:
Для удаления элемента по индексу подходит команда del имя_списка[индекс] :
Кроме того, можно изменить элемент списка в Python (его значение), напрямую к нему обратившись. Но для этого надо знать индекс элемента:
А что нужно сделать, если требуется очистить список в Python? Для этого можно заново его проинициализировать, как будто вновь его создаёте. А чтобы получить доступ к элементу списка, поместите индекс данного элемента в квадратные скобки:
Можно применять и отрицательные индексы (счёт пойдёт с конца). Например, чтобы получить доступ к последнему элементу списка в Python, используют следующую команду:
Также может понадобиться найти и получить из списка некоторый подсписок в заданном диапазоне индексов. Чтобы это реализовать, поместите начальный и конечный индексы в квадратные скобки и разделите их двоеточием:
Объединить списки в Python тоже несложно. Объединение легко сделать с помощью метода extend :
Также в Python можно объединить список с другим, просто добавив их вместе. Это довольно простой способ объединения:
Как видите, объединить списки достаточно легко.
Закрепляем методы списков в Python
Знание соответствующих методов и функций в Python позволит выполнить поиск, добавить нужный элемент, сделать сортировку и т. д. Итак, давайте перечислим основные методы списков и их функции (вспомним те, что уже упоминали, плюс добавим новые): 1. list.append(x) — обеспечивает добавление элемента в конец списка:
2. list.extend(L) — расширяет имеющийся список путем добавления элементов из списка L.
3. list.insert(i, x) — добавляет, а точнее, вставляет элемент х в позицию i. В качестве первого аргумента выступает индекс элемента, после которого вставляется элемент х.
4. list.remove(x) — служит для удаления первого вхождения элемента х, включённого в наш список.
5. list.pop([i]) — обеспечивает удаление элемента из позиции i. Если применять метод без аргумента, удаляется последний элемент, находящийся в списке.
6. list.clear() — просто удаляет все элементы:
7. list.index(x[, start[, end]]) — позволяет вернуть индекс элемента:
8. list.count(x) — возвращает число вхождений элемента х:
9. list.sort(key=None, reverse=False) — сортирует элементы списков по возрастанию. Чтобы выполнить сортировку в обратном порядке используют флаг reverse=True. Кроме того, дополнительные возможности открываются параметром key.
10. list.reverse() — порядок расположения элементов меняется на обратный:
11. list.copy() — копирует списки:
Сортировка с помощью функции sorted()
Давайте ещё раз вернёмся к вопросу сортировки в Python. Чтобы отсортировать данные и найти нужные значения, используют простую встроенную функцию sorted() , принимающую итерируемый тип и возвращающую отсортированный список.
Помните, что функция sorted() возвратит список каждый раз вне зависимости от того, какой тип будет передан.
Идём дальше. Мы уже упоминали ранее метод list.sort() . Так вот, он определён только для списков, зато функция sorted() позволит отсортировать любые итерируемые объекты:
Сортировка по убыванию и возрастанию в Python
Ранее упомянутый параметр reverse есть не только у метода list.sort() , но и у функции sorted() . Он принимает boolean-значение и нужен для сортировки по убыванию либо возрастанию. Ниже мы сортируем учеников по убыванию их возраста:
Стабильность сортировки, сложная сортировка
Начиная с Python версии 2.2, сортировки гарантированно стабильны. Речь о том, что если у записей одинаковые ключи, их порядок не меняется.
Здесь 2 записи с ‘blue’ сохранили изначальный порядок. Данное свойство позволяет сортировать сложные данные путём постепенных сортировок. Например, надо найти и отсортировать данные учеников как по возрасту в возрастающем порядке, так и по оценкам в порядке убывания. Сортировка буде выглядеть так:
Остались вопросы? Хотите поделиться своим личным опытом работы со списками? Нашли ошибку в тексте? Пишите комментарий!
How do I concatenate two lists in Python?
Another alternative has been introduced via the acceptance of PEP 448 which deserves mentioning.
The PEP, titled Additional Unpacking Generalizations, generally reduced some syntactic restrictions when using the starred * expression in Python; with it, joining two lists (applies to any iterable) can now also be done with:
This functionality was defined for Python 3.5, but it hasn’t been backported to previous versions in the 3.x family. In unsupported versions a SyntaxError is going to be raised.
As with the other approaches, this too creates as shallow copy of the elements in the corresponding lists.
The upside to this approach is that you really don’t need lists in order to perform it; anything that is iterable will do. As stated in the PEP:
This is also useful as a more readable way of summing iterables into a list, such as my_list + list(my_tuple) + list(my_range) which is now equivalent to just [*my_list, *my_tuple, *my_range] .
So while addition with + would raise a TypeError due to type mismatch:
The following won’t:
because it will first unpack the contents of the iterables and then simply create a list from the contents.
It’s also possible to create a generator that simply iterates over the items in both lists using itertools.chain() . This allows you to chain lists (or any iterable) together for processing without copying the items to a new list:
How do I concatenate two lists in Python?
As of 3.9, these are the most popular stdlib methods for concatenating two (or more) lists in Python.
Version Restrictions | In-Place? | Generalize to N lists? | |
---|---|---|---|
a+b | — | No | sum([a, b, c], []) 1 |
list(chain(a,b)) 2 | >=2.3 | No | list(chain(a, b, c)) |
[*a, *b] 3 | >=3.5 | No | [*a, *b, *c] |
a += b | — | Yes | No |
a.extend(b) | — | Yes | No |
-
This is a slick solution because of its succinctness. But sum performs concatenation in a pairwise fashion, which means this is a quadratic operation as memory has to be allocated for each step. DO NOT USE if your lists are large.
-
See chain and chain.from_iterable from the docs. You will need to from itertools import chain first. Concatenation is linear in memory, so this is the best in terms of performance and version compatibility. chain.from_iterable was introduced in 2.6.
-
This method uses Additional Unpacking Generalizations (PEP 448), but cannot generalize to N lists unless you manually unpack each one yourself.
-
a += b and a.extend(b) are more or less equivalent for all practical purposes. += when called on a list will internally call list.__iadd__ , which extends the first list by the second.
Performance
2-List Concatenation 1
There’s not much difference between these methods but that makes sense given they all have the same order of complexity (linear). There’s no particular reason to prefer one over the other except as a matter of style.
N-List Concatenation
Plots have been generated using the perfplot module. Code, for your reference.
1. The iadd ( += ) and extend methods operate in-place, so a copy has to be generated each time before testing. To keep things fair, all methods have a pre-copy step for the left-hand list which can be ignored.
Comments on Other Solutions
DO NOT USE THE DUNDER METHOD list.__add__ directly in any way, shape or form. In fact, stay clear of dunder methods, and use the operators and operator functions like they were designed for. Python has careful semantics baked into these which are more complicated than just calling the dunder directly. Here is an example. So, to summarise, a.__add__(b) => BAD; a + b => GOOD.
Some answers here offer reduce(operator.add, [a, b]) for pairwise concatenation — this is the same as sum([a, b], []) only more wordy.
Any method that uses set will drop duplicates and lose ordering. Use with caution.
for i in b: a.append(i) is more wordy, and slower than a.extend(b) , which is single function call and more idiomatic. append is slower because of the semantics with which memory is allocated and grown for lists. See here for a similar discussion.
heapq.merge will work, but its use case is for merging sorted lists in linear time. Using it in any other situation is an anti-pattern.
yield ing list elements from a function is an acceptable method, but chain does this faster and better (it has a code path in C, so it is fast).
6 способов слияния списка списков
Зашел тут у нас в офисе разговор как наиболее «красиво» и быстро склеить список списков в Питоне. Действительно как?
Даже такую казалось бы тривиальную задачу можно решить несколькими способами, существенно отличающимися по скорости и выразительности.
ВАРИАНТ1
Все знают, что элементы списка можно перебирать в цикле и, то что можно добавлять элементы в конец. Это приводит нас к первому варианту решения:
Это самая медленная реализация. Прокол в том что в таком виде оператор «+» в каждом шаге создает новый объект-список, который на следующем шаге выкидывается и т.д.
ВАРИАНТ3
Исправить легко, надо заменить «+» на форму которая не создает новый список, а добавляет к старому. Это оператор «+ #ff7700″>def listmerge3 ( lstlst ) :
all = [ ]
for lst in lstlst:
all . extend ( lst )
return all
Все последующие решения я буду писать через лямбда-выражения, тк они состоят из одного выражения. Имя аргумента сокращено до ll, тк в коде в одну строку это не уменьшает читабельности.
Он чуть чуть быстрее, но все еще тормозной по той же причине, что и его итеративный родственник. Здесь «lambda a,b: a+b» — анонимная функция двух аргументов, которая просто возвращает их сумму. Вариант B это просто шорткат, встроенный в Питон для удобста вычисления суммы элементов. Этот вариант самый короткий.
Лично меня не устраивает ни самый короткий (скорость), ни самый быстрый (красота). Попробуем найти компромисс.
ВАРИАНТ5
С помощью списковых выражений:
Не сильно длиннее предыдущего, но радикально быстрее. Вариант несомненно красив, хотя вложенные списковые выражения не всегда понятны с первого взгляда.
ВАРИАНТ6
А что если попробовать переписать самый быстрый вариант в функцональном стиле? Легко:
Заметьте «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
ДОМАШНЕЕ ЗАДАНИЕ
Предлагаю решить/обсудить более сложную задачу развертывание вложенных списков в линейный.
Пример:
UPD2:
ВАРИАНТ 6Б (от анонимного комментатора в ЖЖ)