{ }codelper

배우기 › Python

더 나아가기 · 25

자료 목록과 열거형

묶음 자료를 목록에 모으고, 정해진 몇 가지 값에는 이름을 붙여요.

이름과 점수처럼 여러 값을 하나로 묶은 묶음 자료를 목록에 차곡차곡 담으면 표 한 장 같은 자료 목록이 돼요.
그리고 "낮음·중간·높음"처럼 정해진 몇 가지 중 하나인 값에는 이름을 붙여 둬요(열거형, enum).
아래 예제는 학생의 이름과 점수를 읽어 등급을 매긴 묶음 자료를 목록에 모으고, 한 줄씩 출력한 다음 등급이 HIGH인 학생의 이름만 골라 출력해요.

from enum import Enum  class Level(Enum):   # 정해진 세 가지 중 하나    LOW = 0    MID = 1    HIGH = 2  def level_of(score):    if score >= 80:        return Level.HIGH    if score >= 60:        return Level.MID    return Level.LOW  n = int(input())students = []   # 묶음 자료(이름, 점수, 등급)의 목록for _ in range(n):    name, score = input().split()    score = int(score)    students.append({"name": name, "score": score, "level": level_of(score)}) for s in students:    print(s["name"], s["score"], s["level"].name) high = []for s in students:    if s["level"] == Level.HIGH:        high.append(s["name"])print("HIGH:", *high)
stdin
4
mina 92
jun 58
sora 75
theo 81
stdout
mina 92 HIGH
jun 58 LOW
sora 75 MID
theo 81 HIGH
HIGH: mina theo

핵심

  • 묶음 자료 하나는 한 사람(한 물건)에 대한 값들의 묶음이에요.
    이것을 목록에 담으면 한 칸이 묶음 자료 하나인 표가 돼요.
    students에서 하나를 꺼낸 s의 이름·점수·등급을 함께 다뤄요.
  • 묶음 자료는 반복문 안에서 바퀴마다 새로 만들어 목록에 넣어요.
    이름 목록, 점수 목록을 따로 두는 것보다 한 사람의 값이 흩어지지 않아서 좋아요.
  • 열거형(enum)은 정해진 몇 가지 값에 이름을 붙인 타입이에요.
    문자열 "HIGH"나 숫자 2를 직접 쓰는 대신 Level.HIGH라고 써요.
    열거형이 있는 언어에서는 Level.HIHG처럼 없는 이름을 쓰면 오류로 알려 줘요(Python은 실행하다가, 나머지는 컴파일할 때).
  • 열거형의 속 값은 언어마다 달라요.
    C, C++, TypeScript, C#은 속이 0, 1, 2 같은 수예요.
    이름을 출력할 때 Java와 C#은 그대로 출력하면 되고, Python은 .name, TypeScript는 Level[값], C와 C++는 이름을 적어 둔 배열에서 꺼내요.
  • 열거형이 없는 JavaScript와 크레이콘은 이름 붙인 상수로 같은 일을 해요.
    코드 곳곳에 2를 쓰는 대신 HIGH라는 이름을 한 번 정해 두고 써요.
  • 점수를 등급으로 바꾸는 일은 함수 하나(levelOf)에 모아요.
    기준이 바뀌어도 한 곳만 고치면 돼요.

언어별로 쓰는 법

Python묶음 자료는 사전 {"name": name, "score": score}로 만들어 students.append(...)로 넣고 s["name"]으로 꺼내요.
@dataclass를 붙인 클래스로 만들면 s.name으로 꺼내요.
열거형은 from enum import Enum 다음 class Level(Enum): 안에 HIGH = 2처럼 적어요.
이름은 level.name, 속 값은 level.value, 이름 문자열로 찾을 때는 Level["HIGH"]
JavaScript묶음 자료는 객체 { name: name, score: score }로 만들어 students.push(...)로 넣고 s.name으로 꺼내요.
변수 이름과 키가 같으면 { name, score }로 줄여 써요.
enum이 없어서 const Level = Object.freeze({ LOW: "LOW", MID: "MID", HIGH: "HIGH" });처럼 얼린 객체를 써요.
얼린 객체는 Level.HIGH = "x"를 해도 바뀌지 않아요.
이 사이트의 채점기처럼 보통 스크립트로 돌리면 오류 없이 무시되고, 엄격 모드("use strict"나 ES 모듈)에서는 TypeError로 멈춰요.
없는 이름 Level.HIHG는 오류가 아니라 undefined예요
TypeScript묶음 자료의 모양은 type Student = { name: string; score: number; level: Level };로 정하고 목록은 Student[].
열거형은 enum Level { LOW, MID, HIGH }이고 속은 0, 1, 2예요.
이름은 Level[s.level]로 얻어요.
문자열 몇 개 중 하나로 정하는 type Level = "LOW" | "MID" | "HIGH";도 많이 써요
Java묶음 자료는 record Student(String name, int score, Level level) {}로 만들고 new Student(...), 꺼낼 때는 s.name().
목록은 List<Student>.
열거형은 enum Level { LOW, MID, HIGH }이고 출력하면 이름이 그대로 나와요.
순서 번호는 level.ordinal(), 이름 문자열로 찾을 때는 Level.valueOf("HIGH")
C#묶음 자료는 record Student(string Name, int Score, Level Level);로 만들고 new Student(...), 꺼낼 때는 s.Name.
목록은 List<Student>.
열거형은 enum Level { LOW, MID, HIGH }이고 출력하면 이름이 나와요.
속 수는 (int)level, 이름 문자열로 찾을 때는 Enum.Parse<Level>("HIGH")
C++묶음 자료는 struct Student { std::string name; int score; Level level; };, 목록은 std::vector<Student>에 push_back({name, score, levelOf(score)}).
열거형은 enum class Level { LOW, MID, HIGH };이고 Level::HIGH로 써요.
enum class는 std::cout에 바로 넣을 수 없고 int로 저절로 바뀌지도 않아서, 이름 배열에서 LEVEL_NAMES[static_cast<int>(s.level)]로 꺼내요
C묶음 자료는 typedef struct { char name[32]; int score; Level level; } Student;, 목록은 배열 Student students[100];에 students[i].score처럼 써요.
열거형은 typedef enum { LOW, MID, HIGH } Level;이고 속은 정수 0, 1, 2예요.
이름을 출력하는 기능이 없어서 LEVEL_NAMES[students[i].level]처럼 이름 배열에서 꺼내요
Craykon구조체가 없어서 묶음 자료는 사전으로 만들어요.
바퀴마다 s = 사전();으로 새로 만들고 s["name"] = ...으로 채운 뒤 students.넣기(s).
enum도 없어서 맨 위에 LOW = 0; MID = 1; HIGH = 2;처럼 이름 붙인 상수를 두고, 이름은 목록 LEVEL_NAMES[s["level"]]에서 꺼내요.
상수를 바꾸지 못하게 막는 기능은 없으니 바꾸지 않기로 약속해요

자주 하는 실수

열거형 값을 문자열이나 수와 비교했어요Python

from enum import Enum
class Level(Enum):
    LOW = 0
    MID = 1
    HIGH = 2
level = Level.HIGH
print(level == "HIGH", level == 2)

→ False False — Level.HIGH는 문자열 "HIGH"도 수 2도 아닌 별개의 값이에요. 오류 없이 거짓이 되어서 찾기 어려워요

level == Level.HIGH처럼 열거형끼리 비교해요.
입력으로 받은 문자열은 Level["HIGH"]로 먼저 열거형으로 바꿔요.

묶음 자료 하나를 고쳐 가며 여러 번 넣었어요JavaScript · TypeScript · Python · Craykon

const s = {};
const students = [];
for (const name of ["mina", "jun"]) {
  s.name = name;
  students.push(s);
}
console.log(students);

→ [ { name: 'jun' }, { name: 'jun' } ] — 목록의 두 칸이 같은 묶음 자료 하나를 가리켜서, 마지막에 적은 값만 남아요

묶음 자료를 반복문 안에서 만들어요(const s = { name: name };).
그러면 바퀴마다 새 묶음 자료가 생겨요.

열거형을 출력했더니 이름이 아니라 수가 나왔어요TypeScript · C · C++

enum Level { LOW, MID, HIGH }
console.log(Level.HIGH);

→ 2 — 속에 든 수가 그대로 나와요. C에서 printf("%d\n", level);, C++에서 enum Level을 std::cout에 넣어도 2예요. C++의 enum class는 std::cout에 넣으면 컴파일 오류예요

TypeScript는 Level[Level.HIGH]로 이름을 얻어요.
C와 C++는 {"LOW", "MID", "HIGH"} 같은 이름 배열을 만들어 거기서 꺼내요.

언어마다 다른 점
열거형이라고 해서 정해진 값만 들어가는 것은 아니에요.
C에서 Level x = 7;은 그대로 컴파일되고 7이 출력돼요.
C#에서 (Level)7을 출력해도 7이에요.
C++의 enum class는 Level x = 7;을 컴파일 오류로 막아 줘요.
밖에서 들어온 수를 열거형으로 바꿀 때는 범위를 먼저 확인해요.

연습 문제