Към съдържанието
wannacode

Списъци

Проблем

Тридесет оценки

Учител пише програма за оценките от контролното. За петима ученици прави пет променливи:

score1 = 62
score2 = 85
score3 = 47
score4 = 91
score5 = 78
total = score1 + score2 + score3 + score4 + score5
print(total)
Изход
363

В класа обаче са тридесет. Тридесет променливи, тридесет събираеми. А за най-високия резултат трябват още двадесет и девет сравнения. Цикълът от миналия урок не помага: той не може да мине през score1, score2, score3, защото това са отделни имена. Трябват ни много стойности под едно име.

Идеята

Списък: редица от кутийки

Списъкът (list) е редица от стойности под едно име. Всяка стойност, елемент на списъка, има номер: индекс. Индексите започват от 0. В Java и C# същото се казва масив.

scores = [62, 85, 47, 91, 78]
print(scores[0])
print(scores[4])
print(len(scores))
scores[2] = 50
print(scores[2])
Изход
62
78
5
50
  • Стойностите са в квадратни скоби [ ], разделени със запетая. Тип не се пише. Може да смесиш числа и текст в един списък, но обикновено всички елементи са от един вид.
  • scores[0] е първият елемент, scores[4] петият. Последният индекс е винаги с 1 по-малък от броя.
  • len(scores) е броят на елементите. Тук е 5.
  • scores[2] = 50 сменя един елемент. Останалите не се променят.

Ако още не знаеш стойностите, но знаеш колко са, умножаваш списък с една нула по броя:

booked = [0] * 3
booked[1] = 2
print(booked)
Изход
[0, 2, 0]

За разлика от масивите в Java и C#, списъкът расте. append добавя елемент в края:

scores = [62, 85]
scores.append(47)
print(scores)
print(len(scores))
Изход
[62, 85, 47]
3

print на цял списък показва елементите му в [ ]. Удобно е за проверка, а за изхода на програмата обикновено печаташ елементите сам.

По-точно, за любопитните
  • Отрицателен индекс брои отзад: scores[-1] е последният елемент, scores[-2] предпоследният.
scores = [62, 85, 47, 91, 78]
print(scores[-1])
print(scores[-2])
Изход
78
91

Пробвай

Кой е кой?

Какво ще отпечата програмата?

prices = [12, 7, 30, 5]
print(prices[1] + prices[3])
Отговор

Идеята

Цикъл през списъка

Сега цикълът вече помага. Броячът i става индексът: минава от 0 до последния и на всеки кръг взима scores[i].

scores = [62, 85, 47, 91, 78]
total = 0
for i in range(len(scores)):
total += scores[i]
print(f"Сума: {total}")
print(f"Средно: {total / len(scores)}")
Изход
Сума: 363
Средно: 72.6

Броячът минава през range(len(scores)): от 0 до len(scores) - 1, точно индексите. Добавиш ли тридесетте оценки в [ ], цикълът не се променя. Това се казва обхождане на списъка.

/ в Python винаги дава дробно число, затова средното излиза 72,6 без нищо допълнително. Целочисленото деление е //.

По-точно, за любопитните

Python има и готови функции за това: sum(scores) е сумата, max(scores) и min(scores) са най-голямото и най-малкото. Тук ги пишем сами, за да видиш как работят. Затова и променливата е total, а не sum: така името sum остава за функцията.

scores = [62, 85, 47, 91, 78]
print(sum(scores), max(scores), min(scores))
Изход
363 91 47

Виж го

Най-високият резултат

Как намираш най-голямото число? Помниш най-голямото засега и го сменяш, щом видиш по-голямо.

scores = [62, 85, 47, 91, 78]
highest = scores[0]
for i in range(1, len(scores)):
if scores[i] > highest:
highest = scores[i]
print(highest) # 91
Стъпка по стъпка, с думи
  1. Пет резултата, едно до друго. Номерата отдолу са индексите: от 0 до 4.
  2. highest започва от първия: scores[0] е 62.
  3. i = 1: 85 > 62, highest става 85.
  4. i = 2: 47 не е по-голямо от 85. Нищо не се сменя.
  5. i = 3: 91 > 85, highest става 91.
  6. i = 4: 78 < 91. range(1, len(scores)) свърши: краят 5 не влиза и цикълът спира.
  7. Най-големият резултат е 91.

highest започва от първия елемент, а не от 0. Ако всички резултати бяха отрицателни, 0 щеше да „спечели“, без да е в списъка. Затова и цикълът започва от range(1, …): първият вече е в highest.

Пробвай

Намери грешката

Програмата трябва да отпечата сумата 363. Вместо това спира с грешка:

Грешка
IndexError: list index out of range

На кой ред е грешката?

Избери реда с грешката.

Идеята

for … in: за всеки елемент

Когато ти трябват само стойностите, а не индексите, има по-кратък цикъл. Колко ученици са взели изпита (60 точки и нагоре)?

scores = [62, 85, 47, 91, 78]
passed = 0
for score in scores:
if score >= 60:
passed += 1
print(f"Взели изпита: {passed}")
Изход
Взели изпита: 4

Чете се „за всяко score в scores“. Това е същият for, само че върви направо по елементите на списъка, а не по числата от range. В Java същото се казва for-each. Няма брояч и индекс, затова не можеш да излезеш извън списъка.

Има и граница: не знаеш на кой индекс си и не можеш да смениш елемента.

По-точно, за любопитните
  • Ако напишеш score = 0 в тялото, сменяш само променливата score. Списъкът остава същият, и Python не те спира:
scores = [62, 85, 47]
for score in scores:
score = 0
print(scores)
Изход
[62, 85, 47]
  • За да смениш елементи или да ти трябва индексът (например за съседа scores[i + 1]), ползвай обикновен for.

Пробвай

Две имена, един списък

Какво ще отпечата програмата?

prices = [10, 20, 30]
sale = prices
sale[0] = 5
print(prices[0])
Отговор
По-точно, за любопитните

Истинско копие правиш с нов списък и цикъл:

prices = [10, 20, 30]
sale = []
for price in prices:
sale.append(price)
sale[0] = 5
print(prices[0], sale[0])
Изход
10 5

Същото дава и prices.copy():

prices = [10, 20, 30]
sale = prices.copy()
sale[0] = 5
print(prices[0], sale[0])
Изход
10 5

Пробвай

Подреди редовете

Програмата трябва да намери най-ниската цена. Подреди редовете ѝ.

  1. print(lowest)
  2. lowest = prices[0]
  3. prices = [18, 7, 25, 12]
  4. for i in range(1, len(prices)):
  5. if prices[i] < lowest:
  6. lowest = prices[i]

Упражнение

Сметки със списък

Реши задачите в редактора си. Всяка програма първо чете колко са числата, после самите числа, по едно на ред:

n = int(input())
numbers = []
for i in range(n):
numbers.append(int(input()))

1. Сума, четни, нечетни. Отпечатай сумата на всички числа, на четните и на нечетните.

Вход
3
1
2
3
Изход
Сума: 6
Четни: 2
Нечетни: 4

2. Обратно. Създай нов списък със същите числа в обратен ред и го отпечатай на един ред.

Вход
5
1
2
3
4
5
Изход
5 4 3 2 1

3. Най-малко, най-голямо, средно. С едно минаване през списъка, без готовите min, max и sum.

Вход
5
4
9
2
7
4
Изход
Най-малко: 2
Най-голямо: 9
Средно: 5.2

Упражнение

Подреждане и броене

4. Сортиране. Подреди числата от най-малкото към най-голямото. Подсказка: минавай през списъка и ако два съседа са в грешен ред, разменяй ги (размяната е от урока за променливите). Повтори, докато няма какво да размениш. Това се казва метод на мехурчето: големите числа „изплуват“ към края. Готовото numbers.sort() не ползвай: целта е да го напишеш сам.

Вход
5
42
7
19
3
25
Изход
3 7 19 25 42

5. Най-дълга поредица. Намери най-дългата поредица от еднакви числа едно след друго.

Вход
8
2
2
5
5
5
1
5
5
Изход
Числото 5, 3 пъти подред

6. Статистика на оценките. Прочети оценки от 2 до 6 и отпечатай колко са от всеки вид. Подсказка: списък counts с 7 елемента, в който оценката е индексът: counts[grade] += 1.

Вход
8
6
4
5
6
3
2
6
5
Изход
Отличен (6): 3
Много добър (5): 2
Добър (4): 1
Среден (3): 1
Слаб (2): 1

Още задачи

  • Медиана. Числото по средата на сортирания списък. За 3, 1, 4, 1, 5 медианата е 3. Ако числата са четен брой, медианата е средното на двете в средата: за 7, 1, 3, 9 е (3 + 7) / 2 = 5.
  • Симетричен списък. Чете ли се еднакво отпред назад и отзад напред? 1 2 3 2 1 е симетричен, 1 2 3 1 не е.
  • Римски цифри. Прочети число от 1 до 3999 и го отпечатай с римски цифри: 2024 е MMXXIV, 1994 е MCMXCIV. Подсказка: два списъка един до друг, със стойностите 1000, 900, 500, 400, 100, …, 1 и със знаците "M", "CM", "D", "CD", "C", …, "I". Докато числото е поне колкото текущата стойност, добавяй знака и вади стойността.

Тест

Провери се

1. В списъка [62, 85, 47, 91, 78] на кой индекс е 91?
2. Кой е индексът на последния елемент на списъка scores?
3. Какво има в списъка веднага след booked = [0] * 3?
4. Цикълът е for i in range(len(scores) + 1): и чете scores[i]. Какво става?
5. sale = prices, после sale[0] = 5. Какво става с prices[0]?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·