Максимум и минимум
Другой вид накопителя хранит лучшее из виденного: самую крупную отгрузку, самую мелкую. Места те же — до цикла, в теле, после; ловушка в начальном значении.
Максимум: запомнить лучшее
Ситуация. Нужна самая крупная отгрузка за день.
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
best := 0
line := 0
for scanner.Scan() {
qty, err := strconv.Atoi(strings.TrimSpace(scanner.Text()))
if err != nil {
fmt.Fprintln(os.Stderr, "Не число:", scanner.Text())
os.Exit(1)
}
line++
if qty > best {
best = qty
}
}
fmt.Println("Строк:", line, "самая крупная:", best)
}Что увидите.
stagiaire@lab:~/gocourse/day08/scratch$ go run . < day.txt
Строк: 4 самая крупная: 40Как это читать. best — «самое крупное из прочитанного»: на каждом проходе новое значение сравнивается с ним и, если больше, становится новым best. Для day.txt (12, 40, 5, 40): 0 → 12 → 40 → 40 → 40.
Не называйте такую переменную max или min: это встроенные функции из дня 04, и переменная их закроет. Программа с одним import "fmt":
max := 0
for qty := 1; qty <= 3; qty++ {
if qty > max {
max = qty
}
}
fmt.Println(max(max, 10))stagiaire@lab:~/gocourse/day08/scratch$ go run .
# day08/scratch
./main.go:12:14: invalid operation: cannot call max (variable of type int): int is not a functionНачальное значение
Ситуация. Та же программа, но нужна самая мелкая отгрузка: меняем знак и имя.
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
least := 0
for scanner.Scan() {
qty, err := strconv.Atoi(strings.TrimSpace(scanner.Text()))
if err != nil {
fmt.Fprintln(os.Stderr, "Не число:", scanner.Text())
os.Exit(1)
}
if qty < least {
least = qty
}
}
fmt.Println("Самая мелкая:", least)
}stagiaire@lab:~/gocourse/day08/scratch$ go run . < day.txt
Самая мелкая: 0Нулевой отгрузки в файле нет, а напечатан 0: ни одно из чисел 12, 40, 5, 40 не меньше нуля, и least ни разу не поменялся. Начальное значение участвует в сравнении как ещё одно число, которого во вводе не было. Надёжное правило: первое значение взять как есть, сравнивать со второго, а какое первое — подскажет номер прохода:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
least := 0
count := 0
for scanner.Scan() {
qty, err := strconv.Atoi(strings.TrimSpace(scanner.Text()))
if err != nil {
fmt.Fprintln(os.Stderr, "Не число:", scanner.Text())
os.Exit(1)
}
if count == 0 || qty < least {
least = qty
}
count++
}
if count == 0 {
fmt.Println("Отгрузок не было")
} else {
fmt.Println("Самая мелкая:", least)
}
}stagiaire@lab:~/gocourse/day08/scratch$ go run . < day.txt
Самая мелкая: 5
stagiaire@lab:~/gocourse/day08/scratch$ go run . < /dev/null
Отгрузок не былоcount == 0 || qty < least — короткое вычисление из дня 06: на первом проходе левая часть истинна, правая не считается. Пустой ввод проверяют после цикла, как среднее на странице 6. У максимума с best := 0 та же ловушка на вводе из одних нулей, и правило «первое как есть» закрывает её.
Попробуйте сейчас: минимум и начальное значение.
Цель: своими запусками увидеть, как начальное значение портит минимум.
1. Наберите в
scratch/main.goвторую программу — с «первое как есть»:✎ Наберите в файлscratch/main.gopackage main import ( "bufio" "fmt" "os" "strconv" "strings" ) func main() { scanner := bufio.NewScanner(os.Stdin) least := 0 count := 0 for scanner.Scan() { qty, err := strconv.Atoi(strings.TrimSpace(scanner.Text())) if err != nil { fmt.Fprintln(os.Stderr, "Не число:", scanner.Text()) os.Exit(1) } if count == 0 || qty < least { least = qty } count++ } if count == 0 { fmt.Println("Отгрузок не было") } else { fmt.Println("Самая мелкая:", least) } }▶ Выполнитеcd ~/gocourse/day08/scratch go run . < day.txt go run . < /dev/null2. Уберите из условия
count == 0 ||, запустите наday.txtснова — вернулся ноль — и верните обратно.3. Третий опыт,
least := 1000вместо правила «первое как есть», — вcourse extra 08.Готово, когда: программа печатает
Самая мелкая: 5и `Отгрузокне было
, а безcount == 0 ||—Самая мелкая: 0`.
Первый или последний
Ситуация. Нужен и размер самой крупной отгрузки, и номер строки. В day.txt число 40 встречается дважды — какую строку назвать?
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
best := 0
bestLine := 0
line := 0
for scanner.Scan() {
qty, err := strconv.Atoi(strings.TrimSpace(scanner.Text()))
if err != nil {
fmt.Fprintln(os.Stderr, "Не число:", scanner.Text())
os.Exit(1)
}
line++
if line == 1 || qty > best {
best = qty
bestLine = line
}
}
fmt.Println("Самая крупная:", best, "в строке", bestLine)
}stagiaire@lab:~/gocourse/day08/scratch$ go run . < day.txt
Самая крупная: 40 в строке 2С qty >= best вместо qty > best:
stagiaire@lab:~/gocourse/day08/scratch$ go run . < day.txt
Самая крупная: 40 в строке 4Строгое > не заменяет best равным значением — запоминается первое из равных; нестрогое >= заменяет — последнее. Какое нужно, говорит условие задачи, а проверить это можно только вводом, где максимум встречается дважды.
Попробуйте сейчас: первый или последний из равных.
Цель: предсказать два числа, которые напечатает программа.
1. Сначала на бумаге: для каждого дня выпишите
qty, сработало ли условие, иbest,bestDayпосле прохода.Код для чтения · разбираем, набирать не нужноbest := 0 bestDay := 0 for day := 1; day <= 4; day++ { qty := day * (5 - day) if qty >= best { best = qty bestDay = day } } fmt.Println(best, bestDay)2. Сдать два числа через пробел —
bestиbestDay:▶ Выполните · выделенное замените своимcourse answer day08.q4 ЧИСЛО ЧИСЛО3. Потом проверьте запуском — программа целиком:
✎ Наберите в файлscratch/main.gopackage main import "fmt" func main() { best := 0 bestDay := 0 for day := 1; day <= 4; day++ { qty := day * (5 - day) if qty >= best { best = qty bestDay = day } } fmt.Println(best, bestDay) }▶ Выполнитеcd ~/gocourse/day08/scratch go run .Готово, когда: пункт
q4вcourse check 08зелёный.
Что может пойти не так
| Что видите | Что это значит | Что делать |
|---|---|---|
| минимум 0, хотя нулей во вводе нет | начальное значение участвует в сравнении | первое взять как есть: условие с count == 0 и «или» |
| назван номер последней из равных строк | стоит >= |
для первой из равных — > |
cannot call max (variable of type int): int is not a function |
переменная max закрыла встроенную функцию |
другое имя: best, least |
Словарик ошибок
К концу дня в ~/errors.md — минимум шестнадцать разборов: вчерашние и сегодняшние. Строка засчитывается, если в ней текст ошибки, тире с пробелами вокруг и что это значило. Сегодняшние собраны в таблицах «Что может пойти не так» на всех семи страницах.
Попробуйте сейчас: словарик и проверка дня.
Цель: словарик пополнен,
course check 08показывает, что осталось.1. Допишите в
~/errors.mdсегодняшние ошибки и выполните:▶ Выполнитеcourse check 082. Звёздочка, в зачёт не входит: задание
biggest.▶ Выполнитеcd ~/gocourse/day08/biggest cat TASK.txt go run . < example.txtНеудобные вводы к нему придумайте сами и проверьте через
printf '…' | go run ..Готово, когда: в
course check 08пунктerrorsзелёный и зачтено не меньше 14 пунктов из 16.
Материал дня закончен. Задания — course lab 08, дополнительное чтение — course extra 08