Счётчик и сумма по группе
Две самые частые работы map на складе: посчитать, сколько раз встретился каждый артикул, и сложить количества по артикулу. Обе пишутся одной строкой — потому что чтение отсутствующего ключа отдаёт ноль.
counts[sku]++
Ситуация. Задача с первой страницы: сколько коробок каждого артикула. Срезами там понадобились цикл в цикле и два среза. С map весь подсчёт — цикл из трёх строк. Сначала предскажите, что он насчитает.
Попробуйте сейчас: сколько ключей.
Цель: предсказать два числа и сдать ответ.
1. Не запуская, прочитайте программу.
counts[sku]++значит то же, чтоcounts[sku] = counts[sku] + 1.Код для чтения · разбираем, набирать не нужноpackage main import "fmt" func main() { counts := map[string]int{} skus := []string{"K-417", "M-120", "K-417", "K-417", "T-118", "M-120"} for _, sku := range skus { counts[sku]++ } fmt.Println(len(counts), counts["M-120"]) }2. Сдайте два числа через пробел:
▶ Выполните · выделенное замените своимcourse answer day18.q3 ЧИСЛО ЧИСЛО3. Проверьте запуском:
✎ Наберите в файлscratch/main.gopackage main import "fmt" func main() { counts := map[string]int{} skus := []string{"K-417", "M-120", "K-417", "K-417", "T-118", "M-120"} for _, sku := range skus { counts[sku]++ } fmt.Println(len(counts), counts["M-120"]) }▶ Выполнитеcd ~/gocourse/day18/scratch go run .Вывод и разбор — под блоком.
Готово, когда: пункт
q3вcourse check 18зелёный.
Что увидите.
3 2Как это читать. В колонке counts — то, что напечатал бы fmt.Println(counts) после строки counts[sku]++:
| проход | sku |
что сделала строка | counts после |
|---|---|---|---|
| 1 | K-417 |
ключа нет: прочитали 0, записали 1 | map[K-417:1] |
| 2 | M-120 |
ключа нет: 0 + 1 | map[K-417:1 M-120:1] |
| 3 | K-417 |
ключ есть: 1 + 1 | map[K-417:2 M-120:1] |
| 4 | K-417 |
2 + 1 | map[K-417:3 M-120:1] |
| 5 | T-118 |
ключа нет: 0 + 1 | map[K-417:3 M-120:1 T-118:1] |
| 6 | M-120 |
1 + 1 | map[K-417:3 M-120:2 T-118:1] |
Проверки «встречался ли артикул» нет и не нужно: для нового артикула чтение отдаёт ноль, ноль плюс один — единица, запись создаёт пару. Разных артикулов три, M-120 — дважды.
Сумма по группе
Ситуация. У каждой коробки есть количество штук, нужна сумма по артикулу. Приём тот же, вместо ++ — +=:
package main
import "fmt"
func main() {
skus := []string{"P-305", "K-417", "P-305", "M-120"}
qtys := []int{4, 10, 6, 1}
totals := map[string]int{}
for i, sku := range skus {
totals[sku] += qtys[i]
}
fmt.Println(totals["P-305"], totals["K-417"], totals["M-120"])
}Что увидите.
10 10 1Как это читать. skus[i] и qtys[i] — одна коробка; for i, sku := range skus из дня 16 отдаёт номер и артикул. totals[sku] += qtys[i] — «прочитать сумму (или ноль), прибавить, записать»: у P-305 4 + 6 = 10.
Тонкость для задания group: запись создаёт пару, даже если прибавили ноль. После totals["C-3"] += 0 ключ C-3 в map есть, и len его считает.
Со ввода — в map
Чтение строк до конца ввода было в дне 08; счётчик встаёт в тот же цикл.
Попробуйте сейчас: счётчик со ввода.
Цель: программа считает артикулы, поданные на ввод, и печатает map целиком.
1. Наберите в черновик:
✎ Наберите в файлscratch/main.gopackage main import ( "bufio" "fmt" "os" "strings" ) func main() { counts := map[string]int{} scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { sku := strings.TrimSpace(scanner.Text()) counts[sku]++ } fmt.Println(len(counts), counts) }2. Подайте три строки через конвейер:
▶ Выполнитеcd ~/gocourse/day18/scratch printf 'K-417\nM-120\nK-417\n' | go run .3. Подайте то же с пустой строкой посередине:
▶ Выполнитеprintf 'K-417\n\nK-417\n' | go run .Готово, когда: на шаге 2 напечатано
2 map[K-417:2 M-120:1], а на шаге 3 вы видите лишнюю пару и знаете, откуда она (таблица ниже).
Печать map через Println годится, чтобы посмотреть, что насчитано. Отчёт печатают по ключам сами — и тут встаёт вопрос порядка: следующая страница.
Что может пойти не так
| Что видите | Что это значит | Что делать |
|---|---|---|
2 map[:1 K-417:2] на вводе с пустой строкой |
пустая строка стала ключом "" |
после TrimSpace: if sku == "" { continue } |
| у каждого артикула ровно 1 | написано counts[sku] = 1 |
counts[sku]++ |
| сумма равна последнему количеству | написано totals[sku] = qtys[i] |
totals[sku] += qtys[i] |
| один артикул — две пары | в строке пробел в конце: "K-417 " — другой ключ |
strings.TrimSpace перед записью |
Дальше: в каком порядке обходится map и как напечатать отчёт по возрастанию — course next