더 나아가기 · 18
2차원 목록(격자)
줄과 칸으로 된 격자: 읽기, 줄 합·칸 합, 이웃 칸을 범위 안에서만 보기.
2차원 목록은 목록을 담은 목록이에요.grid[i][j]는 i번째 줄의 j번째 칸이에요.
아래 예제는 격자를 읽어 줄 합과 칸 합을 구하고, 칸마다 이웃 칸의 합을 찍어요.
r, c = map(int, input().split())grid = [list(map(int, input().split())) for _ in range(r)]print(*[sum(row) for row in grid])print(*[sum(grid[i][j] for i in range(r)) for j in range(c)])moves = [(-1, 0), (1, 0), (0, -1), (0, 1)]near = [[0] * c for _ in range(r)]for i in range(r): for j in range(c): for di, dj in moves: ni, nj = i + di, j + dj if 0 <= ni < r and 0 <= nj < c: near[i][j] += grid[ni][nj]for row in near: print(*row)const [[r, c], ...grid] = require("fs").readFileSync(0, "utf8").trim().split("\n").map((l) => l.trim().split(/\s+/).map(Number));console.log(grid.map((row) => row.reduce((a, b) => a + b, 0)).join(" "));const colSums = Array.from({ length: c }, (_, j) => grid.reduce((s, row) => s + row[j], 0));console.log(colSums.join(" "));const moves = [[-1, 0], [1, 0], [0, -1], [0, 1]];const near = Array.from({ length: r }, () => new Array(c).fill(0));for (let i = 0; i < r; i++) { for (let j = 0; j < c; j++) { for (const [di, dj] of moves) { const ni = i + di, nj = j + dj; if (ni >= 0 && ni < r && nj >= 0 && nj < c) near[i][j] += grid[ni][nj]; } }}for (const row of near) console.log(row.join(" "));import { readFileSync } from "node:fs";const [[r, c], ...grid]: number[][] = readFileSync(0, "utf8").trim().split("\n").map((l) => l.trim().split(/\s+/).map(Number));console.log(grid.map((row) => row.reduce((a, b) => a + b, 0)).join(" "));const colSums: number[] = Array.from({ length: c }, (_, j) => grid.reduce((s, row) => s + row[j], 0));console.log(colSums.join(" "));const moves: [number, number][] = [[-1, 0], [1, 0], [0, -1], [0, 1]];const near: number[][] = Array.from({ length: r }, () => new Array<number>(c).fill(0));for (let i = 0; i < r; i++) { for (let j = 0; j < c; j++) { for (const [di, dj] of moves) { const ni = i + di, nj = j + dj; if (ni >= 0 && ni < r && nj >= 0 && nj < c) near[i][j] += grid[ni][nj]; } }}for (const row of near) console.log(row.join(" "));import java.util.Scanner; public class Main { static void print(int[] a) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < a.length; i++) sb.append(i > 0 ? " " : "").append(a[i]); System.out.println(sb); } public static void main(String[] args) { Scanner sc = new Scanner(System.in); int r = sc.nextInt(), c = sc.nextInt(); int[][] grid = new int[r][c]; for (int i = 0; i < r; i++) for (int j = 0; j < c; j++) grid[i][j] = sc.nextInt(); int[] rowSums = new int[r], colSums = new int[c]; for (int i = 0; i < r; i++) for (int j = 0; j < c; j++) { rowSums[i] += grid[i][j]; colSums[j] += grid[i][j]; } print(rowSums); print(colSums); int[] di = {-1, 1, 0, 0}, dj = {0, 0, -1, 1}; for (int i = 0; i < r; i++) { int[] near = new int[c]; for (int j = 0; j < c; j++) for (int k = 0; k < 4; k++) { int ni = i + di[k], nj = j + dj[k]; if (ni >= 0 && ni < r && nj >= 0 && nj < c) near[j] += grid[ni][nj]; } print(near); } }}using System;using System.Linq; class Program{ static void Main() { int[] rc = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray(); int r = rc[0], c = rc[1]; int[,] grid = new int[r, c]; for (int i = 0; i < r; i++) { int[] row = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray(); for (int j = 0; j < c; j++) grid[i, j] = row[j]; } Console.WriteLine(string.Join(" ", Enumerable.Range(0, r).Select(i => Enumerable.Range(0, c).Sum(j => grid[i, j])))); Console.WriteLine(string.Join(" ", Enumerable.Range(0, c).Select(j => Enumerable.Range(0, r).Sum(i => grid[i, j])))); int[] di = { -1, 1, 0, 0 }, dj = { 0, 0, -1, 1 }; for (int i = 0; i < r; i++) { int[] near = new int[c]; for (int j = 0; j < c; j++) for (int k = 0; k < 4; k++) { int ni = i + di[k], nj = j + dj[k]; if (ni >= 0 && ni < r && nj >= 0 && nj < c) near[j] += grid[ni, nj]; } Console.WriteLine(string.Join(" ", near)); } }}#include <iostream>#include <vector> void print(const std::vector<int>& v) { for (size_t i = 0; i < v.size(); i++) std::cout << (i > 0 ? " " : "") << v[i]; std::cout << '\n';} int main() { int r, c; std::cin >> r >> c; std::vector<std::vector<int>> grid(r, std::vector<int>(c)); for (auto& row : grid) for (int& x : row) std::cin >> x; std::vector<int> rowSums(r, 0), colSums(c, 0); for (int i = 0; i < r; i++) for (int j = 0; j < c; j++) { rowSums[i] += grid[i][j]; colSums[j] += grid[i][j]; } print(rowSums); print(colSums); const int di[] = {-1, 1, 0, 0}, dj[] = {0, 0, -1, 1}; for (int i = 0; i < r; i++) { std::vector<int> near(c, 0); for (int j = 0; j < c; j++) for (int k = 0; k < 4; k++) { int ni = i + di[k], nj = j + dj[k]; if (ni >= 0 && ni < r && nj >= 0 && nj < c) near[j] += grid[ni][nj]; } print(near); }}#include <stdio.h> #define MAX 100 int grid[MAX][MAX]; void print(const int *a, int n) { for (int i = 0; i < n; i++) printf(i > 0 ? " %d" : "%d", a[i]); printf("\n");} int main(void) { int r, c, rowSums[MAX] = {0}, colSums[MAX] = {0}; scanf("%d %d", &r, &c); for (int i = 0; i < r; i++) for (int j = 0; j < c; j++) { scanf("%d", &grid[i][j]); rowSums[i] += grid[i][j]; colSums[j] += grid[i][j]; } print(rowSums, r); print(colSums, c); const int di[] = {-1, 1, 0, 0}, dj[] = {0, 0, -1, 1}; for (int i = 0; i < r; i++) { int near[MAX] = {0}; for (int j = 0; j < c; j++) for (int k = 0; k < 4; k++) { int ni = i + di[k], nj = j + dj[k]; if (ni >= 0 && ni < r && nj >= 0 && nj < c) near[j] += grid[ni][nj]; } print(near, c); } return 0;}rc = 콘솔.수들읽기();r = rc[0];c = rc[1];grid = [];반복 (i = 0; i < r; i++){ grid.넣기(콘솔.수들읽기());}rowSums = 새목록(r, 0);colSums = 새목록(c, 0);반복 (i = 0; i < r; i++){ 반복 (j = 0; j < c; j++) { rowSums[i] += grid[i][j]; colSums[j] += grid[i][j]; }}콘솔.쓰기(rowSums);콘솔.쓰기(colSums);di = [-1, 1, 0, 0];dj = [0, 0, -1, 1];반복 (i = 0; i < r; i++){ near = 새목록(c, 0); 반복 (j = 0; j < c; j++) { 반복 (k = 0; k < 4; k++) { ni = i + di[k]; nj = j + dj[k]; 만약 (ni >= 0 && ni < r && nj >= 0 && nj < c) { near[j] += grid[ni][nj]; } } } 콘솔.쓰기(near);}3 4 1 2 3 4 5 6 7 8 9 10 11 12
10 26 42 15 18 21 24 7 10 13 11 16 24 28 23 15 26 29 19
핵심
- 모든 칸을 보려면 줄을 도는 반복 안에 칸을 도는 반복을 넣어요(겹친 반복).
- 줄 합은 줄마다 칸을 더하고, 칸 합은 칸마다 줄을 따라 내려가며 더해요.
한 번 돌면서rowSums[i]와colSums[j]에 함께 더해도 돼요. - 이웃 칸(위·아래·왼쪽·오른쪽)은 방향을
di = [-1, 1, 0, 0],dj = [0, 0, -1, 1]처럼 목록으로 두고 돌면 짧아져요. - 가장자리에서는 이웃이 바깥으로 나가요.
읽기 전에 꼭0 <= ni < r이고0 <= nj < c인지 확인해요.
음수 쪽도요. - 줄은 하나씩 새로 만들어야 해요.
같은 줄을 여러 번 넣으면 한 칸만 바꿔도 모든 줄이 바뀌어요.
언어별로 쓰는 법
| Python | [[0] * c for _ in range(r)].grid[-1]은 오류가 아니라 마지막 줄이에요 |
|---|---|
| JavaScript | Array.from({ length: r }, () => new Array(c).fill(0)).바깥 칸은 undefined, 바깥 줄에서 칸을 읽으면 TypeError |
| TypeScript | JavaScript와 같아요. 타입은 number[][] |
| Java | new int[r][c] — 모두 0으로 채워져요.범위 밖은 ArrayIndexOutOfBoundsException |
| C# | 직사각형 배열 int[r, c](grid[i, j]로 읽어요)와 배열의 배열 int[r][] 두 가지가 있어요.범위 밖은 IndexOutOfRangeException |
| C++ | vector<vector<int>>(r, vector<int>(c)).[]는 범위를 확인하지 않아요 |
| C | int grid[100][100]처럼 크기를 미리 정해 두고 앞부분만 써요.범위 밖을 읽어도 아무 말이 없어요 |
| Craykon | 줄마다 grid.넣기(콘솔.수들읽기())로 쌓고, 새목록(c, 0)으로 0이 c개인 줄을 만들어요.범위 밖은 "목록에는 0~3번만 있어요" 오류 |
자주 하는 실수
맨 윗줄의 위 이웃을 확인 없이 읽었어요Python
grid = [[1, 2], [3, 4]]
i, j = 0, 0
print(grid[i - 1][j])→ 3 — grid[-1]은 마지막 줄이라 오류 없이 맨 아랫줄 값을 읽어요
0 <= ni < r처럼 음수 쪽도 꼭 확인해요.
범위 확인을 빼먹었어요JavaScript · TypeScript · C · C++
const grid = [[1, 2], [3, 4]];
console.log(1 + grid[0][2]);
console.log(grid[2][0]);→ NaN이 찍히고, 다음 줄은 TypeError로 멈춰요. C·C++은 아무 말 없이 옆 줄이나 엉뚱한 메모리를 읽어요
읽기 전에 0 <= ni && ni < r && 0 <= nj && nj < c를 확인해요.
Java·C#·크레이콘은 범위 오류로 멈춰 줘요.
언어마다 다른 점
Python
JavaScript
Python
[[0] * c] * r는 같은 줄 하나를 r번 가리켜서, g = [[0] * 3] * 2; g[0][0] = 5 하면 [[5, 0, 0], [5, 0, 0]]이 돼요.JavaScript
new Array(r).fill(new Array(c).fill(0))도 똑같으니, 줄은 꼭 하나씩 새로 만드세요.