Введение
Списки Python — основная структура данных, широко используемая в программах Python. Они встречаются в других языках программирования, часто как динамические массивы. Списки — это изменяемый и последовательный тип данных, который позволяет индексацию и срезы. Список может содержать разные типы объектов, включая другие списки.
Синтаксис
- [value1, value2, ...]
- list([iterable])
Замечания
Список это конкретный тип итераций, но не единственный в Python. Иногда лучше использовать множество, кортеж, или словарь.
Списком называют динамические массивы в Python (схоже с vector<void*>
из C++ или Java ArrayList<Object>
). Это не связанный список.
Доступ к элементам осуществляется за константное время и очень быстро. Добавление элементов в конец списка происходит за амортизируемое постоянное время, но иногда включает выделение и копирование списка целиком. Списки включения связаны со списками.
Доступ к значениям списка
Списки Python имеют нулевую индексацию и действуют как массивы в других языках.
lst = [1, 2, 3, 4]
lst[0]
>>>Out: 1
lst[1]
>>>Out: 2
Попытка получить доступ к индексу за пределы списка возбудит IndexError
.
lst[4]
>>>Out: IndexError: list index out of range
Отрицательные показатели интерпретируются как отсчет от конца списка.
lst[-1]
>>>Out: 4
lst[-2]
>>>Out: 3
lst[-5]
>>>Out: IndexError: list index out of range
Это функционально эквивалентно
lst[len(lst)-1]
>>>Out: 4
Списки позволяют использовать ломтик обозначение , как lst[start:end:step]
.Выход среза обозначений представляет собой новый список , содержащий элементы из индекса start
до end-1
.Если параметры опущены start
значения по умолчанию для начала списка, end
в конец списка и step
1:
lst[1:]
>>>Out: [2, 3, 4]
lst[:3]
>>>Out: [1, 2, 3]
lst[::2]
>>>Out: [1, 3]
lst[::-1]
>>>Out: [4, 3, 2, 1]
lst[-1:0:-1]
>>>Out: [4, 3, 2]
lst[5:8] # так как стартовый индекс больше длины списка, то возвращается пустой список
>>>Out: []
lst[1:10] # то же самое, что опустить конечныый индекс
>>>Out: [2, 3, 4]
Имея это в виду, вы можете распечатать обратную версию списка, вызвав
lst[::-1]
>>>Out: [4, 3, 2, 1]
При использовании длин шагов с отрицательными значениями начальный индекс должен быть больше конечного индекса, в противном случае результатом будет пустой список.
lst[3:1:-1]
>>>Out: [4, 3]
Использование индексов отрицательных шагов эквивалентно следующему коду:
list(reversed(lst[0:2]))
>>>Out: [2, 1]
Используемые индексы на 1 меньше, чем используемые при отрицательной индексации, и обращены.
Продвинутый срез
Когда списки нарезали, то вызывается __getitem__()
метод объекта списка со slice
объектом. В Python есть встроенный метод среза для генерации объектов среза. Мы можем использовать это , чтобы сохранить кусочек и использовать его позже , как показано ниже,
data = 'chandan purohit 22 2000' #предполагаем, что поля данных фиксированной длины
name_slice = slice(0,19)
age_slice = slice(19,21)
salary_slice = slice(22,None)
#теперь мы можем получить более читабельные срезы
print(data[name_slice])
>>>Out: 'chandan purohit'
print(data[age_slice])
>>>Out: 22
print(data[salary_slice])
>>>Out: 2000
Это может быть очень полезным, предоставляя функциональность для нарезки наших объектов путем переопределения __getitem__
в нашем классе.
Доступ к значениям во вложенном списке
Начиная с трехмерного списка:
alist = [[[1,2],[3,4]], [[5,6,7],[8,9,10], [12, 13, 14]]]
Доступ к элементам в списке:
print(alist[0][0][1]) #доступ ко второму элементу первого списка в первом списке
>>>Out: 2
print(alist[1][1][2]) #доступ к третьему элементу второго списка во втором списке
>>>Out: 10
Выполнение вспомогательных операций:
alist[0][0].append(11) #добавляем 11 в конец первого списка в первом списке
print(alist[0][0][2])
>>>Out: 11
Использование вложенных циклов for
для печати списка:
#один из вариантов циклического перебора вложенных списков
for row in alist:
for col in row:
print(col)
>>>Out: [1, 2, 11]
[3, 4]
[5, 6, 7]
[8, 9, 10]
[12, 13, 14]
Обратите внимание, что эта операция может использоваться для списка включения или даже в качестве генератора для повышения эффективности, например:
[col for row in alist for col in row]
>>Out: [[1, 2, 11], [3, 4], [5, 6, 7], [8, 9, 10], [12, 13, 14]]
Не все элементы во внешних списках должны быть самими списками:
alist[1].insert(2, 15)
#вставляем 15 в третью позицию во втором списке
Еще один способ использовать вложенные циклы. Другой способ лучше, но мне нужно было использовать это иногда:
#менее характерный для Python способ перебора списка
for row in range(len(alist)):
for col in range(len(alist[row])):
print(alist[row][col])
>>>Out: [1, 2]
[3, 4]
[5, 6, 7]
[8, 9, 10]
15
[12, 13, 14]
Использование фрагментов во вложенном списке:
print(alist[1][1:])
>>>Out: [[8, 9, 10], 15, [12, 13, 14]]
#Срезы все равно работают
Финальный список:
print(alist)
>>>Out: [[[1, 2], [3, 4]], [[5, 6, 7], [8, 9, 10], 15, [12, 13, 14]]]
Any() и All()
Вы можете использовать all()
, чтобы определить , если все значения итератора вычисляют значение True
nums = [1, 1, 0, 1]
all(nums)
>>>Out: False
chars = ['a', 'b', 'c', 'd']
all(chars)
>>>Out: True
Аналогично, any()
определяет , является ли одно или более значений в качестве итератора оценки True
nums = [1, 1, 0, 1]
any(nums)
>>>Out: True
vals = [None, None, None, False]
any(vals)
>>>Out: False
Хотя в этом примере используется список, важно отметить, что эти встроенные модули работают с любыми итерациями, включая генераторы.
vals = [1, 2, 3, 4]
any(val > 12 for val in vals)
>>>Out: False
any((val * 2) > 6 for val in vals)
>>>Out: True
Проверка, если список пуст
Пустота списка связана с булевым значением False
, так что вам не надо проверять len(lst) == 0
, а только lst
или not lst
lst = []
if not lst:
print("список пуст")
>>>Out: 'список пуст'
Проверка наличия элемента в списке
Python позволяет очень просто проверить, есть ли элемент в списке. Просто используйте in
операторе.
lst = ['test', 'twest', 'tweast', 'treast']
'test' in lst
>>>Out: True
'toast' in lst
>>>Out: False
Примечание: in
оператора на множествах асимптотически быстрее , чем в списках. Если вам нужно использовать его много раз на потенциально большие списках, вы можете превратить ваш list
в set
, и проверить наличие элементов на set
.
slst = set(lst)
'test' in slst
>>>Out: True
Сравнение списков
Можно сравнивать списки и другие последовательности лексикографически, используя операторы сравнения. Оба операнда должны быть одного типа.
[1, 10, 100] < [2, 10, 100]
#Истина, поскольку 1 < 2
>>>Out: True
[1, 10, 100] < [1, 10, 100]
#Ложь, потому что списки равны
>>>Out: False
[1, 10, 100] <= [1, 10, 100]
#Истина, потому что списки равны
>>>Out: True
[1, 10, 100] < [1, 10, 101]
# Истина, поскольку 100 < 101
>>>Out: True
[1, 10, 100] < [0, 10, 100]
# Ложь, потому что 0 < 1
>>>Out: False
Если один из списков содержится в начале другого, выигрывает самый короткий список.
[1, 10] < [1, 10, 100]
>>>Out: True
Объединение и слияние списков
Самый простой способ конкатенации list1
и list2
:
merged = list1 + list2
zip
возвращает список кортежей, где I-й кортеж содержит I-й элемент из каждого из аргументов последовательностей или итерируемыми:
alist = ['a1', 'a2', 'a3']
blist = ['b1', 'b2', 'b3']
for a, b in zip(alist, blist):
print(a, b)
>>>Out: a1 b1
a2 b2
a3 b3
Если списки имеют разную длину, результат будет включать в себя столько элементов, сколько самый короткий:
alist = ['a1', 'a2', 'a3']
blist = ['b1', 'b2', 'b3', 'b4']
for a, b in zip(alist, blist):
print(a, b)
>>>Out: a1 b1
a2 b2
a3 b3
alist = []
len(list(zip(alist, blist)))
>>>Out: 0
Для заполнения списков неравной длины до самого длинного с использованием None
из itertools.zip_longest
(не забудьте в python 3 импортировать библиотеку)
import itertools
alist = ['a1', 'a2', 'a3']
blist = ['b1']
clist = ['c1', 'c2', 'c3', 'c4']
for a,b,c in itertools.zip_longest(alist, blist, clist):
print(a, b, c)
>>>Out: a1 b1 c1
a2 None c2
a3 None c3
None None c4
Вставка значений в определенный индекс:
alist = [123, 'xyz', 'zara', 'abc']
alist.insert(3, [2009])
print("Финальный список :", alist)
Результат:
>>>Out: Финальный список: [123, 'xyz', 'zara', 2009, 'abc']
Инициализация списка с фиксированным числом элементов
Для неизменяемых элементов (например , None
, строковые литералы и т.д.):
my_list = [None] * 10
my_list = ['test'] * 10
Для изменяемых элементов, та же конструкция , приведет все элементы списка со ссылкой на тот же объект, например, для набора:
my_list=[{1}] * 10
print(my_list)
>>>Out: [{1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}]
my_list[0].add(2)
print(my_list)
>>>Out: [{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}]
Вместо того , чтобы инициализировать список с фиксированным числом различных изменяемых объектов, используйте:
my_list=[{1} for _ in range(10)]
Перебор списка
Python поддерживает использование цикла for
непосредственно для списка:
my_list = ['foo', 'bar', 'baz']
for item in my_list:
print(item)
>>>Out: foo
bar
baz
Вы также можете получить позицию каждого элемента одновременно:
for (index, item) in enumerate(my_list):
print('Элемент в позиции {}: {}'.format(index, item))
>>>Out: Элемент в позиции 0: foo
Элемент в позиции 1: bar
Элемент в позиции 2: baz
Другой способ итерации списка на основе значения индекса:
for i in range(0,len(my_list)):
print(my_list[i])
>>>Out: foo
bar
baz
Обратите внимание, что изменение элементов в списке во время итерации может привести к неожиданным результатам:
for item in my_list:
if item == 'foo':
del my_list[0]
print(item)
>>>Out: foo
baz
В этом последнем примере, мы удалили первый элемент в первой итерации, это стало причиной пропуска bar
.
Длина списка
Используйте len()
, чтобы получить одномерный длину списка.
len(['one', 'two']) #возращает 2
>>>Out: 2
len(['one', [2, 3], 'four']) # возращает 3, а 4
>>>Out: 3
len()
также работает на строках, словарях и других структурах данных, подобных списку.
Обратите внимание, что len()
является встроенной функцией, а не методом объекта списка.
Также обратите внимание , что стоимость len()
является O(1)
, то есть он будет тратить такое же количество времени, чтобы получить длину списка, независимо от его длины.
Список методов и поддерживаемых операторов
Начиная с данным списком a
:
a = [1, 2, 3, 4, 5]
append(value)
- добавляет новый элемент в конец списка.
# Append добавляет 6, 7, and 7 к списку
a.append(6)
a.append(7)
a.append(7)
a
>>>Out: [1, 2, 3, 4, 5, 6, 7, 7]
# Добавление к другому списку
b = [8, 9]
a.append(b)
a
>>>Out: [1, 2, 3, 4, 5, 6, 7, 7, [8, 9]]
# Добавляем элемент другого типа, элементы списка не обязательно должны быть одного типа
my_string = "hello world"
a.append(my_string)
a
>>>Out: [1, 2, 3, 4, 5, 6, 7, 7, [8, 9], "hello world"]
Обратите внимание , что append()
метод только добавляет один новый элемент в конец списка. Если вы добавляете список в другой список, добавляемый вами список становится единым элементом в конце первого списка.
# добавляем список в другой список
a = [1, 2, 3, 4, 5, 6, 7, 7]
b = [8, 9]
a.append(b)
a
>>>Out: [1, 2, 3, 4, 5, 6, 7, 7, [8, 9]]
a[8] # возращается [8, 9]
>>>Out: [8,9]
extend(enumerable)
- расширяет список путем добавления элементов из другого перечисляемого.
a = [1, 2, 3, 4, 5, 6, 7, 7]
b = [8, 9, 10]
# расширяем список через добавление всех элементов из b
a.extend(b)
a
>>>Out: [1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10]
# расширяем список элементами из неспискового перечисляемого:
a.extend(range(3))
a
>>>Out: [1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 0, 1, 2]
Списки также могут быть объединены с +
оператора. Обратите внимание, что это не изменяет ни один из исходных списков:
a = [1, 2, 3, 4, 5, 6] + [7, 7] + b
a
>>>Out: [1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10]
insert(index, value)
- вставляет value
непосредственно перед указанным значение индекса index
. Таким образом, после вставки нового элемента занимает позицию index
.
a.insert(0, 0) # вставляем 0 в позицию 0
a.insert(2, 5) # вставляем 5 в позицию 2
a
>>>Out: [0, 1, 5, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10]
remove(value)
- удаляет первое вхождение заданного значения. Если прилагаемое значение не может быть найдено, то вызывается ValueError
.
a.remove(0)
a.remove(9)
a
>>>Out: [1, 5, 2, 3, 4, 5, 6, 7, 7, 8, 10]
a.remove(10) # [1, 5, 2, 3, 4, 5, 6, 7, 7, 8]
a.remove(10)
# числе 10 не входит в массив a
>>>Out: ValueError: list.remove(x): x not in list
reverse()
- изменяет список на месте и возвращает None
.
a.reverse()
a
>>>Out: [8, 7, 7, 6, 5, 4, 3, 2, 1]
Есть также другие способы реверсирования списка .
count(value)
- подсчитывает количество вхождений некоторого значения в списке.
a.count(7) #возращает 2
>>>Out: 2
sort()
- сортирует список в числовом и лексикографическом порядке и возвращает None
.
a.sort() # сортировка списка в числовом порядке
a
>>>Out: [1, 2, 3, 4, 5, 6, 7, 7, 8]
Списки также могут быть отменены при сортировке с помощью reverse=True
, флага в своем sort()
методе.
a.sort(reverse=True)
# a = [8, 7, 6, 5, 4, 3, 2, 1]
Если вы хотите сортировать по атрибутам элементов, вы можете использовать key
ключевого слова аргумента:
import datetime
class Person(object):
def __init__(self, name, birthday, height):
self.name = name
self.birthday = birthday
self.height = height
def __repr__(self):
return self.name
l = [Person("John Cena", datetime.date(1992, 9, 12), 175),
Person("Chuck Norris", datetime.date(1990, 8, 28), 180),
Person("Jon Skeet", datetime.date(1991, 7, 6), 185)]
l.sort(key=lambda item: item.name)
l
>>>Out: [Chuck Norris, John Cena, Jon Skeet]
l.sort(key=lambda item: item.birthday)
l
>>>Out: [Chuck Norris, Jon Skeet, John Cena]
l.sort(key=lambda item: item.height)
l
>>>Out: [John Cena, Chuck Norris, Jon Skeet]
В случае списка словарей концепция одинакова:
import datetime
l = [{'name':'John Cena', 'birthday': datetime.date(1992, 9, 12),'height': 175},
{'name': 'Chuck Norris', 'birthday': datetime.date(1990, 8, 28),'height': 180},
{'name': 'Jon Skeet', 'birthday': datetime.date(1991, 7, 6), 'height': 185}]
l.sort(key=lambda item: item['name'])
l
>>>Out: [Chuck Norris, John Cena, Jon Skeet]
l.sort(key=lambda item: item['birthday'])
l
>>>Out: [Chuck Norris, Jon Skeet, John Cena]
l.sort(key=lambda item: item['height'])
l
>>>Out: [John Cena, Chuck Norris, Jon Skeet]
Сортировать по субсловарям:
import datetime
l = [{'name':'John Cena', 'birthday': datetime.date(1992, 9, 12),'size': {'height': 175, 'weight': 100}},
{'name': 'Chuck Norris', 'birthday': datetime.date(1990, 8, 28),'size' : {'height': 180, 'weight': 90}},
{'name': 'Jon Skeet', 'birthday': datetime.date(1991, 7, 6), 'size': {'height': 185, 'weight': 110}}]
l.sort(key=lambda item: item['size']['weight'])
l
>>>Out: [{'name': 'Chuck Norris',
'birthday': datetime.date(1990, 8, 28),
'size': {'height': 180, 'weight': 90}},
{'name': 'John Cena',
'birthday': datetime.date(1992, 9, 12),
'size': {'height': 175, 'weight': 100}},
{'name': 'Jon Skeet',
'birthday': datetime.date(1991, 7, 6),
'size': {'height': 185, 'weight': 110}}]
Лучший способ разобраться с помощью attrgetter
и itemgetter
Списки также могут быть отсортированы с помощью функции attrgetter
и itemgetter
из модуля оператора. Это может помочь улучшить читаемость и возможность повторного использования. Вот несколько примеров,
from operator import itemgetter,attrgetter
people = [{'name':'chandan','age':20,'salary':2000},
{'name':'chetan','age':18,'salary':5000},
{'name':'guru','age':30,'salary':3000}]
by_age = itemgetter('age')
by_salary = itemgetter('salary')
people.sort(key=by_age) #in-place sorting by age
people.sort(key=by_salary) #in-place sorting by salary
itemgetter
также может быть дан индекс. Это полезно, если вы хотите сортировать на основе индексов кортежа.
list_of_tuples = [(1,2), (3,4), (5,0)]
list_of_tuples.sort(key=itemgetter(1))
print(list_of_tuples)
>>>Out: [(5, 0), (1, 2), (3, 4)]
Используйте attrgetter
, если вы хотите сортировать по атрибутам объекта:
persons = [Person("John Cena", datetime.date(1992, 9, 12), 175),
Person("Chuck Norris", datetime.date(1990, 8, 28), 180),
Person("Jon Skeet", datetime.date(1991, 7, 6), 185)] #повторное использования класса Person из примера выше
persons.sort(key=attrgetter('name')) #сортирует по 'name'
by_birthday = attrgetter('birthday')
persons.sort(key=by_birthday) #сортирует по 'birthday'
persons
>>>Out: [Chuck Norris, Jon Skeet, John Cena]
clear()
- удаляет все элементы из списка
a.clear()
a
>>>Out: []
Репликация - умножая существующий список на целое число будет производить больший список , состоящий из того, что многие копии оригинала. Это может быть полезно, например, для инициализации списка:
a = ["blah"] * 3
a
>>>Out: ["blah", "blah", "blah"]
b = [1, 3, 5] * 5
b
>>>Out: [1, 3, 5, 1, 3, 5, 1, 3, 5, 1, 3, 5, 1, 3, 5]
Будьте внимательны делая это , если список содержит ссылки на объекты (например , список списков).
Удаление элемента - можно удалить несколько элементов в списке , используя del
ключевые слова и ломтик обозначение:
a = list(range(10))
del a[::2]
a
>>>Out: [1, 3, 5, 7, 9]
del a[-1]
a
>>>Out: [1, 3, 5, 7]
del a[:]
>>>Out: []
копирование
Назначение по умолчанию "=" назначает ссылку на исходный список новому имени. Таким образом, исходное имя и новое имя указывают на один и тот же объект списка. Изменения, сделанные с помощью одного из них, будут отражены в другом Это часто не то, что вы хотели.
a = [1, 2, 3, 4, 5]
b = a
a.append(6)
b
>>>Out: [1, 2, 3, 4, 5, 6]
Если вы хотите создать копию списка, у вас есть варианты ниже.
Вы можете нарезать это:
old_list = [1,2,3,4]
new_list = old_list[:]
Вы можете использовать встроенную функцию list()
:
new_list = list(old_list)
Вы можете использовать универсальный copy.copy()
:
import copy
new_list = copy.copy(old_list) #вставляет ссылки на объекты найденные в оригинале
Это немного медленнее, чем list()
, потому что он должен сначала выяснить тип данных old_list
.
Если список содержит объекты, и вы также хотите скопировать их, используйте generic copy.deepcopy()
:
import copy
new_list = copy.deepcopy(old_list) #inserts copies of the objects found in the original.
Очевидно, самый медленный и самый требующий памяти метод, но иногда неизбежный.
copy()
- возвращает неполную копию списка
aa = a.copy()
# aa = [1, 2, 3, 4, 5]
Удалить повторяющиеся значения в списке
Удаление повторяющихся значений в списке может быть сделано путем преобразования списка в set
(то есть неупорядоченный набор различных объектов). Если необходим список, то множество может быть преобразовано обратно в список с помощью функции list()
:
names = ["aixk", "duke", "edik", "tofp", "duke"]
list(set(names))
>>>Out: ['duke', 'tofp', 'aixk', 'edik']
Обратите внимание, что при преобразовании списка в набор исходный порядок теряется.
Для того, чтобы сохранить порядок списка можно использовать OrderedDict
import collections
>>> collections.OrderedDict.fromkeys(names).keys()
# Out: ['aixk', 'duke', 'edik', 'tofp']
Реверсирование элементов списка
Вы можете использовать функцию reversed
, которая возвращает итератор обращенного списка:
rev = reversed(numbers)
rev
>>>Out: [9, 8, 7, 6, 5, 4, 3, 2, 1]
Обратите внимание, что список «чисел» остается неизменным этой операцией и остается в том же порядке, в котором он был изначально.
Чтобы изменить на месте, вы можете также использовать в reverse
метод .
Вы также можете изменить список (фактически получая копию, исходный список не затрагивается), используя синтаксис срезов, задав третий аргумент (шаг) как -1:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
numbers[::-1]
>>>Out: [9, 8, 7, 6, 5, 4, 3, 2, 1]