오늘이 이 코스에서 가장 중요한 날이다. 이 세 개(+find/some/every/sort)만 자연스러워지면 for 루프를 거의 안 쓰게 된다. Rust의 이터레이터 체이닝(.map().filter().collect())과 사고방식이 사실상 똑같다 — .collect()가 필요 없을 뿐.
이후 예제에서 이 로그 배열을 계속 쓴다:
const log = [
{ time: "09:00", tempC: 52.3, throttled: false },
{ time: "10:00", tempC: 67.8, throttled: false },
{ time: "11:00", tempC: 81.2, throttled: true },
{ time: "12:00", tempC: 60.0, throttled: false },
{ time: "13:00", tempC: 65.0, throttled: false },
];
const fahrenheits = log.map((entry) => entry.tempC * 9/5 + 32);
// [126.14, 154.04, 178.16, 140, 149]
const times = log.map((entry) => entry.time);
// ["09:00", "10:00", "11:00", "12:00", "13:00"]
const warnings = log.filter((entry) => entry.tempC >= 65);
// 67.8, 81.2, 65.0 세 개의 entry 객체
(누적값, 현재원소) => 새누적값. 초기값을 생략하면 첫 원소가 초기값이 되는데, 헷갈리니 항상 명시한다.
const total = log.reduce((sum, entry) => sum + entry.tempC, 0);
const avg = total / log.length;
const maxTemp = log.reduce((max, entry) => Math.max(max, entry.tempC), -Infinity);
log.find((e) => e.throttled) // 조건 만족하는 첫 entry 객체 (없으면 undefined)
log.some((e) => e.tempC >= 80) // 하나라도 만족하면 true
log.every((e) => e.tempC < 100) // 전부 만족해야 true
[...log].sort((a, b) => a.tempC - b.tempC);
// sort는 원본을 수정하므로 스프레드로 복사부터. 숫자 비교는 (a,b)=>a-b 관용구
[1, 2, 10].sort()는 [1, 10, 2]가 된다 — 기본 정렬은 "문자열로 변환 후" 비교라서다. 숫자 정렬은 항상 비교 함수를 넘긴다.
log.filter(e => e.tempC >= 65).map(e => e.time) — "경고 이상인 시간대만 뽑기"가 한 줄.
_submissions/day05.js이 문서 상단의 log 배열을 그대로 파일 안에 선언하고 시작한다.
과제 1. 경고 시간대 추출
65°C 이상인 항목의 time만 뽑은 배열을 리턴하는 warningTimes(log)를 작성한다 (filter + map 체이닝).
// warningTimes(log) → ["10:00", "11:00", "13:00"]
과제 2. 화씨 변환 + 평균
avgFahrenheit(log): 모든 항목을 화씨로 바꾼 뒤 평균을 리턴한다 (map 다음 reduce).
과제 3. 통계 요약
summarize(log): { avg, max, min, throttledCount } 객체를 리턴한다. avg/max/min은 소수점 첫째 자리까지.
과제 4 (도전). 정렬된 상위 N
topHottest(log, n): 온도가 높은 순으로 정렬한 뒤 상위 n개의 time만 담은 배열을 리턴한다 (원본 log는 훼손하지 않을 것 — 스프레드로 복사 후 정렬).
cd ~/Documents/javascript-2주완성
bun _grade.ts day05