Списъци
Проблем
Тридесет оценки
Учител пише програма за оценките от контролното. За петима ученици прави пет променливи:
score1 = 62score2 = 85score3 = 47score4 = 91score5 = 78total = score1 + score2 + score3 + score4 + score5print(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] = 50print(scores[2])6278550- Стойностите са в квадратни скоби
[ ], разделени със запетая. Тип не се пише. Може да смесиш числа и текст в един списък, но обикновено всички елементи са от един вид.
scores[0]е първият елемент,scores[4]петият. Последният индекс е винаги с 1 по-малък от броя.len(scores)е броят на елементите. Тук е 5.scores[2] = 50сменя един елемент. Останалите не се променят.
Ако още не знаеш стойностите, но знаеш колко са, умножаваш списък с една нула по броя:
booked = [0] * 3booked[1] = 2print(booked)[0, 2, 0]За разлика от масивите в Java и C#, списъкът расте. append добавя елемент в края:
scores = [62, 85]scores.append(47)print(scores)print(len(scores))[62, 85, 47]3print на цял списък показва елементите му в [ ]. Удобно е за проверка, а за изхода на програмата обикновено печаташ елементите сам.
По-точно, за любопитните
- Отрицателен индекс брои отзад:
scores[-1]е последният елемент,scores[-2]предпоследният.
scores = [62, 85, 47, 91, 78]print(scores[-1])print(scores[-2])7891Пробвай
Кой е кой?
Какво ще отпечата програмата?
prices = [12, 7, 30, 5]print(prices[1] + prices[3])Броим от 0: prices[1] е 7 (вторият), prices[3] е 5 (четвъртият). 7 + 5 = 12. Ако броиш от 1, ще вземеш 12 и 30.
Идеята
Цикъл през списъка
Сега цикълът вече помага. Броячът i става индексът: минава от 0 до последния и на всеки кръг взима scores[i].
scores = [62, 85, 47, 91, 78]total = 0for 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Стъпка по стъпка, с думи
- Пет резултата, едно до друго. Номерата отдолу са индексите: от 0 до 4.
- highest започва от първия: scores[0] е 62.
- i = 1: 85 > 62, highest става 85.
- i = 2: 47 не е по-голямо от 85. Нищо не се сменя.
- i = 3: 91 > 85, highest става 91.
- i = 4: 78 < 91. range(1, len(scores)) свърши: краят 5 не влиза и цикълът спира.
- Най-големият резултат е 91.
highest започва от първия елемент, а не от 0. Ако всички резултати бяха отрицателни, 0 щеше да „спечели“, без да е в списъка. Затова и цикълът започва от range(1, …): първият вече е в highest.
Пробвай
Намери грешката
Програмата трябва да отпечата сумата 363. Вместо това спира с грешка:
IndexError: list index out of rangeНа кой ред е грешката?
Избери реда с грешката.
range(1, len(scores) + 1) брои от 1 до 5, като номерата на учениците. Индексите на списък с 5 елемента обаче са от 0 до 4: scores[5] няма и програмата спира с IndexError. Това се казва излизане извън списъка. А scores[0] щеше да е пропуснат. Поправката е range(len(scores)).Идеята
for … in: за всеки елемент
Когато ти трябват само стойностите, а не индексите, има по-кратък цикъл. Колко ученици са взели изпита (60 точки и нагоре)?
scores = [62, 85, 47, 91, 78]passed = 0for score in scores: if score >= 60: passed += 1print(f"Взели изпита: {passed}")Взели изпита: 4Чете се „за всяко score в scores“. Това е същият for, само че върви направо по елементите на списъка, а не по числата от range. В Java същото се казва for-each. Няма брояч и индекс, затова не можеш да излезеш извън списъка.
Има и граница: не знаеш на кой индекс си и не можеш да смениш елемента.
По-точно, за любопитните
- Ако напишеш
score = 0в тялото, сменяш само променливатаscore. Списъкът остава същият, и Python не те спира:
scores = [62, 85, 47]for score in scores: score = 0print(scores)[62, 85, 47]- За да смениш елементи или да ти трябва индексът (например за съседа
scores[i + 1]), ползвай обикновенfor.
Пробвай
Две имена, един списък
Какво ще отпечата програмата?
prices = [10, 20, 30]sale = pricessale[0] = 5print(prices[0])b = a и после b = 5 не сменя a. При списъка sale = prices не прави нов списък, а дава второ име на същия. Затова промяната през sale се вижда и през prices. Защо е така, ще разберем в модул „Класове и обекти“: списъкът е обект, а променливата сочи към него.По-точно, за любопитните
Истинско копие правиш с нов списък и цикъл:
prices = [10, 20, 30]sale = []for price in prices: sale.append(price)sale[0] = 5print(prices[0], sale[0])10 5Същото дава и prices.copy():
prices = [10, 20, 30]sale = prices.copy()sale[0] = 5print(prices[0], sale[0])10 5Пробвай
Подреди редовете
Програмата трябва да намери най-ниската цена. Подреди редовете ѝ.
print(lowest)lowest = prices[0]prices = [18, 7, 25, 12]for i in range(1, len(prices)):if prices[i] < lowest:lowest = prices[i]
Упражнение
Сметки със списък
Реши задачите в редактора си. Всяка програма първо чете колко са числата, после самите числа, по едно на ред:
n = int(input())numbers = []for i in range(n): numbers.append(int(input()))1. Сума, четни, нечетни. Отпечатай сумата на всички числа, на четните и на нечетните.
3123Сума: 6Четни: 2Нечетни: 42. Обратно. Създай нов списък със същите числа в обратен ред и го отпечатай на един ред.
5123455 4 3 2 13. Най-малко, най-голямо, средно. С едно минаване през списъка, без готовите min, max и sum.
549274Най-малко: 2Най-голямо: 9Средно: 5.2Упражнение
Подреждане и броене
4. Сортиране. Подреди числата от най-малкото към най-голямото. Подсказка: минавай през списъка и ако два съседа са в грешен ред, разменяй ги (размяната е от урока за променливите). Повтори, докато няма какво да размениш. Това се казва метод на мехурчето: големите числа „изплуват“ към края. Готовото numbers.sort() не ползвай: целта е да го напишеш сам.
5427193253 7 19 25 425. Най-дълга поредица. Намери най-дългата поредица от еднакви числа едно след друго.
822555155Числото 5, 3 пъти подред6. Статистика на оценките. Прочети оценки от 2 до 6 и отпечатай колко са от всеки вид. Подсказка: списък counts с 7 елемента, в който оценката е индексът: counts[grade] += 1.
864563265Отличен (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". Докато числото е поне колкото текущата стойност, добавяй знака и вади стойността.
Тест