더 나아가기 · 24
세기, 누적 계산, 묶기
한 번 훑으면서 조건에 맞는 것을 세고, 지금까지의 값을 들고 다니고, 열쇠별로 묶어요.
세기, 누적, 묶기는 자료를 한 번 훑으면서 답을 만들어 가는 세 가지 기본 꼴이에요.
아래 예제는 점수를 하나씩 보면서 지금까지의 합과 최고 점수를 찍고, 80점 이상이 몇 개인지 세고, 점수를 60점대·70점대처럼 십의 자리로 묶어 찍어요.
scores = list(map(int, input().split()))count = 0 # 80점 이상인 점수의 개수total = 0 # 지금까지의 합best = scores[0] # 지금까지의 최고 점수groups = {} # 십의 자리(60, 70, …) → 그 묶음의 점수들for s in scores: if s >= 80: count += 1 total += s if s > best: best = s print(total, best) key = s // 10 * 10 if key not in groups: groups[key] = [] # 처음 보는 열쇠면 빈 목록부터 groups[key].append(s)print(count)for key in sorted(groups): print(f"{key}:", *groups[key])const scores = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let count = 0; // 80점 이상인 점수의 개수let total = 0; // 지금까지의 합let best = scores[0]; // 지금까지의 최고 점수const groups = new Map(); // 십의 자리(60, 70, …) → 그 묶음의 점수들for (const s of scores) { if (s >= 80) count++; total += s; if (s > best) best = s; console.log(total + " " + best); const key = Math.floor(s / 10) * 10; if (!groups.has(key)) groups.set(key, []); // 처음 보는 열쇠면 빈 목록부터 groups.get(key).push(s);}console.log(count);for (const key of [...groups.keys()].sort((a, b) => a - b)) { console.log(key + ": " + groups.get(key).join(" "));}import { readFileSync } from "node:fs";const scores: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let count = 0; // 80점 이상인 점수의 개수let total = 0; // 지금까지의 합let best = scores[0]; // 지금까지의 최고 점수const groups = new Map<number, number[]>(); // 십의 자리(60, 70, …) → 그 묶음의 점수들for (const s of scores) { if (s >= 80) count++; total += s; if (s > best) best = s; console.log(total + " " + best); const key = Math.floor(s / 10) * 10; let group = groups.get(key); if (group === undefined) { // 처음 보는 열쇠면 빈 목록부터 group = []; groups.set(key, group); } group.push(s);}console.log(count);for (const key of [...groups.keys()].sort((a, b) => a - b)) { console.log(key + ": " + groups.get(key)!.join(" "));}import java.util.*; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); List<Integer> scores = new ArrayList<>(); while (in.hasNextInt()) scores.add(in.nextInt()); int count = 0; // 80점 이상인 점수의 개수 int total = 0; // 지금까지의 합 int best = scores.get(0); // 지금까지의 최고 점수 Map<Integer, List<Integer>> groups = new TreeMap<>(); // 십의 자리 → 그 묶음의 점수들(열쇠 순) for (int s : scores) { if (s >= 80) count++; total += s; if (s > best) best = s; System.out.println(total + " " + best); int key = s / 10 * 10; if (!groups.containsKey(key)) groups.put(key, new ArrayList<>()); // 처음 보는 열쇠면 빈 목록부터 groups.get(key).add(s); } System.out.println(count); for (int key : groups.keySet()) { StringBuilder line = new StringBuilder(key + ":"); for (int s : groups.get(key)) line.append(" ").append(s); System.out.println(line); } }}using System;using System.Collections.Generic;using System.Linq; class Program{ static void Main() { int[] scores = Console.ReadLine().Split().Select(int.Parse).ToArray(); int count = 0; // 80점 이상인 점수의 개수 int total = 0; // 지금까지의 합 int best = scores[0]; // 지금까지의 최고 점수 var groups = new SortedDictionary<int, List<int>>(); // 십의 자리 → 그 묶음의 점수들(열쇠 순) foreach (int s in scores) { if (s >= 80) count++; total += s; if (s > best) best = s; Console.WriteLine(total + " " + best); int key = s / 10 * 10; if (!groups.ContainsKey(key)) groups[key] = new List<int>(); // 처음 보는 열쇠면 빈 목록부터 groups[key].Add(s); } Console.WriteLine(count); foreach (int key in groups.Keys) { Console.WriteLine(key + ": " + string.Join(" ", groups[key])); } }}#include <iostream>#include <map>#include <vector> int main() { std::vector<int> scores; int x; while (std::cin >> x) scores.push_back(x); int count = 0; // 80점 이상인 점수의 개수 int total = 0; // 지금까지의 합 int best = scores[0]; // 지금까지의 최고 점수 std::map<int, std::vector<int>> groups; // 십의 자리 → 그 묶음의 점수들(열쇠 순) for (int s : scores) { if (s >= 80) count++; total += s; if (s > best) best = s; std::cout << total << ' ' << best << '\n'; int key = s / 10 * 10; groups[key].push_back(s); // 없는 열쇠면 []가 빈 vector를 만들어 줘요 } std::cout << count << '\n'; for (const auto& [key, group] : groups) { std::cout << key << ':'; for (int s : group) std::cout << ' ' << s; std::cout << '\n'; }}#include <stdio.h> int main(void) { int scores[100], n = 0; while (n < 100 && scanf("%d", &scores[n]) == 1) n++; int count = 0; // 80점 이상인 점수의 개수 int total = 0; // 지금까지의 합 int best = scores[0]; // 지금까지의 최고 점수 // 사전이 없어서 묶음을 배열로: groups[6]이 60점대(점수는 0~100), sizes[6]이 그 개수 int groups[11][100], sizes[11] = {0}; for (int i = 0; i < n; i++) { int s = scores[i]; if (s >= 80) count++; total += s; if (s > best) best = s; printf("%d %d\n", total, best); int key = s / 10; groups[key][sizes[key]++] = s; } printf("%d\n", count); for (int key = 0; key <= 10; key++) { if (sizes[key] == 0) continue; // 비어 있는 묶음은 건너뛰어요 printf("%d:", key * 10); for (int j = 0; j < sizes[key]; j++) printf(" %d", groups[key][j]); printf("\n"); } return 0;}scores = 콘솔.수들읽기();count = 0; // 80점 이상인 점수의 개수total = 0; // 지금까지의 합best = scores[0]; // 지금까지의 최고 점수groups = 사전(); // 십의 자리(60, 70, …) → 그 묶음의 점수들각각 (s 에서 scores){ 만약 (s >= 80) { count++; } total += s; 만약 (s > best) { best = s; } 콘솔.쓰기(total + " " + best); key = 수학.몫(s, 10) * 10; 만약 (!groups.있나(key)) { groups[key] = []; // 처음 보는 열쇠면 빈 목록부터 } groups[key].넣기(s);}콘솔.쓰기(count);keys = groups.열쇠목록;keys.정렬();각각 (key 에서 keys){ 콘솔.쓰기(key + ": " + groups[key].잇기(" "));}72 85 90 68 85 77 93
72 72 157 85 247 90 315 90 400 90 477 90 570 93 4 60: 68 70: 72 77 80: 85 85 90: 90 93
핵심
- 세기는 0에서 시작해서 조건에 맞을 때만 1을 더해요.
합계와 달리 값이 아니라 1을 더해요. - 누적 값은 하나를 볼 때마다 고쳐 쓰는 변수예요.
지금까지의 합(total), 지금까지의 최고(best)처럼 '여기까지의 답'을 늘 들고 있어서, 중간 결과를 그 자리에서 찍을 수 있어요.
반복문 단원에서 본total += i가 바로 이 꼴이에요. - 누적 변수는 반복 앞에서 만들어요.
개수와 합은 0에서, 최고·최저는 첫 값에서 시작해요. - 묶기는 값마다 열쇠를 정하고(예제는 68 → 60, 72 → 70), 사전에서 그 열쇠의 목록에 값을 넣어요.
세는 사전(사전 단원)은 값이 수였고, 묶는 사전은 값이 목록이에요. - 처음 보는 열쇠에는 아직 목록이 없어요.
빈 목록을 먼저 만들어 넣고, 그다음에 값을 넣어요. - 세 가지를 따로 돌 필요는 없어요.
예제는 반복문 하나에서 세기·누적·묶기를 함께 해요.
언어별로 쓰는 법
| Python | 세기 count += 1(한 줄로는 sum(1 for s in scores if s >= 80)), 누적 total += s.묶기는 예제처럼 if key not in groups: groups[key] = [] 다음에 groups[key].append(s), 짧게는 groups.setdefault(key, []).append(s)나 collections.defaultdict(list) |
|---|---|
| JavaScript | 세기 count++(한 줄로는 scores.filter((s) => s >= 80).length), 누적 total += s.묶기는 Map에 if (!groups.has(key)) groups.set(key, []); 다음에 groups.get(key).push(s) |
| TypeScript | JavaScript와 같고 new Map<number, number[]>()처럼 타입을 적어요.groups.get(key)는 undefined일 수도 있는 타입이라 바로 .push하면 타입 오류(TS2532)예요.예제처럼 꺼낸 값을 변수에 받아 undefined인지 확인해요 |
| Java | 세기 count++(한 줄로는 scores.stream().filter(s -> s >= 80).count()), 누적 total += s.묶기는 Map<Integer, List<Integer>>에 containsKey로 확인하고 put(key, new ArrayList<>()), 짧게는 groups.computeIfAbsent(key, k -> new ArrayList<>()).add(s).TreeMap이면 열쇠 순으로 돌아요 |
| C# | 세기 count++(LINQ로는 scores.Count(s => s >= 80)), 누적 total += s.묶기는 Dictionary<int, List<int>>에 if (!groups.ContainsKey(key)) groups[key] = new List<int>(); 다음에 groups[key].Add(s).SortedDictionary면 열쇠 순으로 돌아요 |
| C++ | 세기 count++(<algorithm>의 std::count_if도 있어요), 누적 total += s.묶기는 std::map<int, std::vector<int>>에 groups[key].push_back(s) 한 줄이에요.없는 열쇠면 []가 빈 vector를 만들어 줘요 |
| C | 세기와 누적은 다른 언어와 같아요(count++, total += s).사전이 없어서 묶기는 손으로 해요. 열쇠가 작은 정수면 예제처럼 2차원 배열에 groups[key][sizes[key]++] = s로 넣고, 묶음마다 개수(sizes)를 따로 세요 |
| Craykon | 세기 count++, 누적 total += s.묶기는 사전()에 만약 (!groups.있나(key)) { groups[key] = []; } 다음에 groups[key].넣기(s).열쇠 순으로 찍으려면 groups.열쇠목록을 정렬()해서 돌아요 |
자주 하는 실수
+=를 =+로 썼어요
int count = 0;
int scores[] = {72, 85, 90};
for (int i = 0; i < 3; i++)
if (scores[i] >= 80) count =+ 1;
printf("%d\n", count);→ 1 — 오류 없이 돌지만 2가 아니에요. count =+ 1은 count = +1, 곧 "1을 넣어라"예요
count += 1로 써요.
개수가 늘 1로 나오면 이 글자 순서부터 확인해요.
누적 변수를 반복 안에서 0으로 만들었어요
const scores = [72, 85, 90];
for (const s of scores) {
let total = 0;
total += s;
console.log(total);
}→ 72, 85, 90 — 바퀴마다 0으로 돌아가서 합이 쌓이지 않아요
total의 시작 값(0)은 반복 앞에서 한 번만 주고, 반복 안에서는 더하기만 해요.let·int 같은 만드는 낱말이 없는 Python과 크레이콘도 total = 0이 반복 안에 있으면 똑같이 72, 85, 90이 나와요.
빈 목록을 만들지 않고 묶음에 넣었어요Java
Map<Integer, List<Integer>> groups = new TreeMap<>();
int s = 68;
int key = s / 10 * 10;
groups.get(key).add(s);→ NullPointerException — 없는 열쇠라서 get이 null을 돌려줬어요
먼저 if (!groups.containsKey(key)) groups.put(key, new ArrayList<>());를 하거나, groups.computeIfAbsent(key, k -> new ArrayList<>()).add(s)로 써요.
언어마다 다른 점
묶음마다 목록을 따로 만들어야 해요.
Python에서
예제처럼 처음 보는 열쇠마다 새
묶음마다 목록을 따로 만들어야 해요.
Python에서
groups = dict.fromkeys([60, 70], [])로 열쇠를 미리 만들어 두면 모든 열쇠가 같은 목록 하나를 함께 써서, 68과 72를 따로 넣어도 {60: [68, 72], 70: [68, 72]}가 돼요.예제처럼 처음 보는 열쇠마다 새
[]를 만들어요.