Масиви
Проблем
Тридесет оценки
Учител пише програма за оценките от контролното. За петима ученици прави пет променливи:
const score1 = 62;const score2 = 85;const score3 = 47;const score4 = 91;const score5 = 78;const sum = score1 + score2 + score3 + score4 + score5;console.log(sum);363В класа обаче са тридесет. Тридесет променливи, тридесет събираеми. А за най-високия резултат трябват още двадесет и девет сравнения. Цикълът от миналия урок не помага: той не може да мине през score1, score2, score3, защото това са отделни имена. Трябват ни много стойности под едно име.
Идеята
Масив: редица от кутийки
Масивът (array) е редица от стойности под едно име. Всяка стойност, елемент на масива, има номер: индекс. Индексите започват от 0.
const scores = [62, 85, 47, 91, 78];console.log(scores[0]);console.log(scores[4]);console.log(scores.length);scores[2] = 50;console.log(scores[2]);6278550- Стойностите са в квадратни скоби
[ ], разделени със запетая. Тип не се пише. Може да смесиш числа и текст в един масив, но обикновено всички елементи са от един вид.
scores[0]е първият елемент,scores[4]петият. Последният индекс е винаги с 1 по-малък от броя.scores.lengthе броят на елементите. Тук е 5.scores[2] = 50;сменя един елемент. Останалите не се променят.
Ако още не знаеш стойностите, но знаеш колко са, създаваш масив с размер и го пълниш с нули:
const booked = new Array(3).fill(0);booked[1] = 2;console.log(booked);[ 0, 2, 0 ]За разлика от масивите в Java и C#, масивът расте. push добавя елемент в края:
const scores = [62, 85];scores.push(47);console.log(scores);console.log(scores.length);[ 62, 85, 47 ]3console.log на цял масив показва елементите му в [ ]. Удобно е за проверка, а за изхода на програмата обикновено печаташ елементите сам.
По-точно, за любопитните
new Array(3)без.fill(0)не съдържа нули, а три празни места. Прочетеш ли едно от тях, получавашundefined, „няма стойност“:
const booked = new Array(3);console.log(booked);console.log(booked[0]);[ <3 empty items> ]undefinedconstпред масива значи, че името винаги сочи същия масив. Елементите му пак може да се сменят и да се добавят.
Пробвай
Кой е кой?
Какво ще отпечата програмата?
const prices = [12, 7, 30, 5];console.log(prices[1] + prices[3]);Броим от 0: prices[1] е 7 (вторият), prices[3] е 5 (четвъртият). 7 + 5 = 12. Ако броиш от 1, ще вземеш 12 и 30.
Идеята
Цикъл през масива
Сега цикълът вече помага. Броячът i става индексът: минава от 0 до последния и на всеки кръг взима scores[i].
const scores = [62, 85, 47, 91, 78];let sum = 0;for (let i = 0; i < scores.length; i++) { sum += scores[i];}console.log(`Сума: ${sum}`);console.log(`Средно: ${sum / scores.length}`);Сума: 363Средно: 72.6Условието е i < scores.length, а не число. Добавиш ли тридесетте оценки в [ ], цикълът не се променя. Това се казва обхождане на масива.
В JavaScript / дели точно, затова средното излиза 72,6 без нищо допълнително.
Виж го
Най-високият резултат
Как намираш най-голямото число? Помниш най-голямото засега и го сменяш, щом видиш по-голямо.
const scores = [62, 85, 47, 91, 78];let max = scores[0];for (let i = 1; i < scores.length; i++) { if (scores[i] > max) { max = scores[i]; }}console.log(max); // 91Стъпка по стъпка, с думи
- Пет резултата, едно до друго. Номерата отдолу са индексите: от 0 до 4.
- max започва от първия: scores[0] е 62.
- i = 1: 85 > 62, max става 85.
- i = 2: 47 не е по-голямо от 85. Нищо не се сменя.
- i = 3: 91 > 85, max става 91.
- i = 4: 78 < 91. После i става 5, 5 < scores.length е невярно и цикълът спира.
- Най-големият резултат е 91.
max започва от първия елемент, а не от 0. Ако всички резултати бяха отрицателни, 0 щеше да „спечели“, без да е в масива. Затова и цикълът започва от i = 1: първият вече е в max.
Пробвай
Намери грешката
Програмата трябва да отпечата сумата 363. Вместо това отпечатва NaN.
На кой ред е грешката?
Избери реда с грешката.
<= цикълът прави още един кръг, с i = 5. Индексите на масива с 5 елемента са от 0 до 4, елемент scores[5] няма. Това се казва излизане извън масива. В Java и C# програмата спира с грешка. В JavaScript не спира: scores[5] е undefined („няма стойност“), а 363 + undefined е NaN (Not a Number, „не е число“). Програмата върви с грешен резултат, затова гледай изхода. Поправката е i < scores.length.Идеята
for … of: за всеки елемент
Когато ти трябват само стойностите, а не индексите, има по-кратък цикъл. Колко ученици са взели изпита (60 точки и нагоре)?
const scores = [62, 85, 47, 91, 78];let passed = 0;for (const score of scores) { if (score >= 60) { passed++; }}console.log(`Взели изпита: ${passed}`);Взели изпита: 4Чете се „за всяко score от (of) scores“. В Java същото се казва for-each. Няма брояч и индекс, затова не можеш да излезеш извън масива. const е, защото score в един кръг не се сменя: следващият кръг получава ново score.
Има и граница: не знаеш на кой индекс си и не можеш да смениш елемента.
По-точно, за любопитните
- Ако напишеш
score = 0;в тялото, програмата спира сTypeError, защотоscoreеconst. Сlet scoreщеше да смени само променливата, а масивът щеше да остане същият.
const scores = [62, 85, 47];try { for (const score of scores) { score = 0; }} catch (error) { console.log(`${error.name}: ${error.message}`);}TypeError: Assignment to constant variable.- Има и
for … in, сinвместоof. Той не дава елементите, а индексите, и то като текст. За масиви пишиfor … of:
const scores = [62, 85, 47];for (const i in scores) { console.log(i, typeof i);}0 string1 string2 string- За да смениш елементи или да ти трябва индексът (например за съседа
scores[i + 1]), ползвай обикновенfor.
Пробвай
Две имена, един масив
Какво ще отпечата програмата?
const prices = [10, 20, 30];const sale = prices;sale[0] = 5;console.log(prices[0]);let b = a; и после b = 5; не сменя a. При масивите sale = prices не прави нов масив, а дава второ име на същия. Затова промяната през sale се вижда и през prices. Защо е така, ще разберем в модул „Класове и обекти“: масивът е обект, а променливата сочи към него.По-точно, за любопитните
Истинско копие правиш с нов масив и цикъл:
const prices = [10, 20, 30];const sale = [];for (const price of prices) { sale.push(price);}sale[0] = 5;console.log(prices[0], sale[0]);10 5Същото дава и [...prices]:
const prices = [10, 20, 30];const sale = [...prices];sale[0] = 5;console.log(prices[0], sale[0]);10 5Пробвай
Подреди редовете
Програмата трябва да намери най-ниската цена. Подреди редовете ѝ.
min = prices[i];let min = prices[0];if (prices[i] < min) {const prices = [18, 7, 25, 12];for (let i = 1; i < prices.length; i++) {}}console.log(min);
Упражнение
Сметки с масив
Реши задачите в редактора си. Всяка програма първо чете колко са числата, после самите числа, по едно на ред:
const n = Number(await ask(""));const numbers = [];for (let i = 0; i < n; i++) { numbers.push(Number(await ask("")));}Най-горе са редовете за ask(), а накрая rl.close(), както в урока „Вход и изход“.
1. Сума, четни, нечетни. Отпечатай сумата на всички числа, на четните и на нечетните.
3123Сума: 6Четни: 2Нечетни: 42. Обратно. Създай нов масив със същите числа в обратен ред и го отпечатай на един ред.
5123455 4 3 2 13. Най-малко, най-голямо, средно. С едно минаване през масива.
549274Най-малко: 2Най-голямо: 9Средно: 5.2Упражнение
Подреждане и броене
4. Сортиране. Подреди числата от най-малкото към най-голямото. Подсказка: минавай през масива и ако два съседа са в грешен ред, разменяй ги (размяната е от урока за променливите). Повтори, докато няма какво да размениш. Това се казва метод на мехурчето: големите числа „изплуват“ към края.
5427193253 7 19 25 425. Най-дълга поредица. Намери най-дългата поредица от еднакви числа едно след друго.
822555155Числото 5, 3 пъти подред6. Статистика на оценките. Прочети оценки от 2 до 6 и отпечатай колко са от всеки вид. Подсказка: масив counts с 7 елемента, в който оценката е индексът: counts[grade]++.
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". Докато числото е поне колкото текущата стойност, добавяй знака и вади стойността.
Тест