Упорядоченный список (list)

Упорядоченный список

Часто в программах требуется хранить различные списки данных, например, список городов, число выигранных очков в серии игр, или значения некоторой функции:

Москва
Санкт-Петербург
Самара
Казань
Тверь
1200
200
500
210
0100

0.5
0.55
0.6
0.4

Все это можно представить в виде упорядоченного списка, который в Python задается с помощью оператора квадратных скобок:

[элемент1, элемент2, …, элементN]

Например, для хранения городов можно задать такой список:

lst = ["Москва", "Санкт-Петербург", "Тверь", "Казань"]

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

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

Если мы посмотрим тип объекта, на который ссылается переменая lst:

type(lst)

то увидим значение «list». Это как раз и есть тип списка.

То есть, через переменную lst мы можем работать со списком в целом, и первое, что нас здесь интересует: как обратиться к определенному элементу этого списка?

Для этого используется такой синтаксис:

список[индекс]

Например,

lst[0]
lst[2]

Но, если мы укажем не существующий индекс:

lst[5]

то возникнет ошибка. Чтобы этого избежать нам надо знать значение последнего индекса. Для этого можно воспользоваться функцией

len(список)

которая возвращает число элементов в списке:

len(lst)

вернет значение 4. Но, так как индексы начинаются с нуля, то последний индекс будет равен:

lastIndex = len(lst) – 1

То есть, можно записать вот так:

lst[len(lst)-1]

но можно и проще, вот так:

lst[-1]

Этот пример показывает, что при отрицательных индексах, мы начинаем движение с конца списка и значение -1 дает самый последний элемент.

Далее, для перебора элементов списка в Python очень удобно использовать цикл for:

lst = ["Москва", "Санкт-Петербург", "Тверь", "Казань"]
for city in lst:
   print(city)

Смотрите, как это легко и просто делается!

Конечно, мы можем распечатать весь контейнер целиком, просто записав:

print(lst)

Но здесь нет перебора всех элементов, а просто печать содержимого.

Вернемся к циклу. Здесь переменная city будет ссылаться на элементы внутри списка lst. Давайте выведем в консоль дополнительно еще тип выводимого значения:

print(city, type(city))

Увидим везде строковый тип str.

Но раз city ссылается на элементы списка, можно ли их изменить, присвоив этой переменной другое значение?

city = "новое значение"

Если мы теперь выведем список lst в консоль:

print(lst)

то окажется, что список не изменился. Почему?

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

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

Все предыдущие типы, что мы проходили на прошлых занятиях относились к неизменяемым.

Это были:

числа, булевые значения, строки

Но вот список list относится к изменяемым типам, то есть, мы можем изменить его состояние, не создавая нового объекта.

В самом простом случае мы можем воспользоваться таким синтаксисом:

список[индекс] = значение

Например, так:

lst[0] = "Самара"

Теперь первый элемент не «Москва», а «Самара». В действительности, здесь произошло следующее:

Мы поменяли значение ссылки lst[0] первого элемента списка. Изначально она ссылалась на объект «Москва», а затем, стала ссылаться на объект «Самара». Прежний объект автоматически удаляется сборщиком мусора.

Вот так происходит изменение элементов списка, то есть, меняются значения ссылок на новые объекты.

Теперь вернемся к вопросу изменения элементов списка внутри цикла for. Предположим, у нас имеется список чисел:

digs = [-1, 0, 5, 3, 2]

и в цикле мы хотим его изменить на их квадраты.

Для этого запишем цикл в таком виде:

digs = [-1, 0, 5, 3, 2]
for x in range(5):
    digs[x] **= 2   #digs[x] = digs[x]**2
print(digs)

Или, чтобы не указывать конкретное число в функции range, ее можно переписать так (вместо for x in range(5):)

for x in range(len(digs)):

И программа будет работать со списком произвольной длины.

Во всех наших примерах мы создавали списки небольшой длины и потому могли их запросто записать в программе.

Но что если требуется создать список размерностью в 100 или 1000 элементов? Для этого можно воспользоваться такой конструкцией, например:

A = [0]*1000

создает список из 1000 элементов со значением 0. Фактически, мы здесь сначала создали список из одного нулевого элемента, а затем, размножили его до тысячи. Или, можно сделать так:

A = ["none"]*100

Получим 100 элементов со строкой «none». И так далее. Кстати, если требуется создать пустой список, то это будет так:

A = []

Ну хорошо, есть у нас список из 100 или 1000 или другого числа элементов. Но как нам теперь с ним работать, например, занести туда какие-либо данные.

Для наглядности, предположим, пользователь вводит N чисел с клавиатуры (N<100) и пока он вводит положительные значения, мы их добавляем в список.

Как только он ввел какое-либо отрицательное число, считывание прекращается и мы вычисляем среднее арифметическое введенных значений.

Это можно реализовать так:

digs = [0]*100
N = 0; x = 0
while x >= 0:
   x = int(input("Введите целое число: "))
   digs[N] = x
   N += 1
 
S = 0
for x in range(N):
    S += digs[x]
S = S/N;
 
print("S = %f, N = %d"%(S, N))

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

Список может состоять из произвольных данных, например:

t = ["строка", 5, 5.7, True, [1,2,3]]

Причем, его длина

len(t)

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

И этот пример показывает как можно создавать двумерные списки:

A = [[1,2,3], [4,5,6], [7,8,9]]

Для доступа к конкретному числу следует сначала обратиться к первому списку:

A[1]

а, затем, ко второму:

A[1][0]

Получим значение 4. С этими списками можно выполнять все те же самые операции, о которых мы говорили ранее, например, изменить значение:

A[1][2] = -1

Далее, списки можно объединять друг с другом, используя оператор +:

[1,2,3] + ["Москва", "Тверь"]

Используя этот оператор, можно добавлять новые элементы к списку:

digs = [1,2,3,4]
digs = digs + [5]
digs += [6]

или в начало:

digs = ["числа"]+digs

И здесь обратите внимание, что мы объединяем именно списки, то есть, вот такая запись:

digs = digs+3

приведет к ошибке, т.к. 3 – это число, а не список.

Следующий оператор:

3 in digs

возвращает True, если элемент, записанный слева, присутствует в списке, указанный справа. Иначе, значение False:

-1 in digs

Или, можно делать так:

[1,2,3] in A

То есть, в качестве элемента может быть любой тип данных.

Следующие две полезные функции:

digs = [1,2,3,4]
max(digs)
min(digs)

находят минимальное или максимальное числовое значение. И если в списке имеется не числовой элемент:

digs += "a"

то эти функции приводят к ошибкам.

Также можно вычислять сумму элементов числового списка:

d = [1,2,3,4]
sum(d)

выполнять сортировку чисел по возрастанию:

d = [-1, 0, 5, 3, 2, 5]
sorted(d)

или, по убыванию:

sorted(d, reverse=True)

Эта функция возвращает новый объект-список, прежний d остается без изменений.

Наконец, можно сравнивать списки между собой:

[1,2,3] == [1,2,3]
[1,2,3] != [1,2,3]
[1,2,3] > [1,2,3]

В последнем сравнении получим False, т.к. списки равны, но если записать так:

[10,2,3] > [1,2,3]

то первый список будет больше второго. Здесь сравнение больше, меньше выполняется по тому же принципу, что и у строк: перебираются последовательно элементы, и если текущий элемент первого списка больше соответствующего элемента второго списка, то первый список больше второго. И аналогично, при сравнении меньше:

[10,2,3] < [1,2,3]

Все эти сравнения работают с однотипными данными:

[1,2, "abc"] > [1,2, "abc"]

сработает корректно, а вот так:

[1,2,3] > [1,2, "abc"]

Произойдет ошибка, т.к. число 3 не может быть сравнено со строкой «abc».

https://www.youtube.com/watch?v=ImWIDeW4GH0&list=PLA0M1Bcd0w8xIdFNA95aQrwJ_GQJEV8ko