본문 바로가기
Project/ReceiptMind

📊 Swift로 주간 수입·지출 요약 만들기

by 밤새는 탐험가89 2025. 7. 29.
728x90
SMALL

– weeklySummary 함수 분석과 고차함수 filter 완전 이해하기


🧭 이 글의 목적

 iOS 앱에서 주간 단위로 수입과 지출을 요약해서 보여주는 화면을 만들고 싶을 때, 아래처럼 날짜별로 정리된 데이터가 필요합니다.

[
  ("Mon", 12000.0, 3000.0),
  ("Tue", 0.0, 5500.0),
  ("Wed", 0.0, 0.0),
  ...
  ("Sun", 5000.0, 10000.0)
]

 

이번 글에서는 이를 가능하게 해주는 weeklySummary라는 함수를 소개하고, 그 핵심인 고차함수 filter의 사용 이유와 구조를 상세히 분석합니다.


✅ weeklySummary 함수 – 무슨 역할을 할까?

🔹 함수 정의

func weeklySummary(in baseDate: Date) -> [(day: String, income: Double, expense: Double)]

🔹 주요 목적

  1. 기준 날짜(baseDate)가 속한 "한 주간의 시작일(월요일)"을 계산
  2. 월요일부터 일요일까지 반복하며
  3. 각 날짜에 해당하는 수입(income)지출(expense) 총합을 구함
  4. 결과를 (요일 문자열, 수입 총합, 지출 총합) 튜플 형태로 반환

이 함수는 주간 요약 통계를 보여주기 위한 데이터 소스로 매우 유용하며, 그래프, 표, 리스트 UI 등에 바로 활용 가능합니다.


🧩 함수 전체 코드

func weeklySummary(in baseDate: Date) -> [(day: String, income: Double, expense: Double)] {
    let calendar = Calendar.current
    let startOfWeek = calendar.date(from: calendar.dateComponents([.yearForWeekOfYear, .weekOfYear], from: baseDate))!

    var result: [(String, Double, Double)] = []
    let formatter = DateFormatter()
    formatter.dateFormat = "EEE"

    for i in 0..<7 {
        guard let day = calendar.date(byAdding: .day, value: i, to: startOfWeek) else { continue }

        let incomeForDay = transactions.filter {
            $0.transaction == .income && calendar.isDate($0.date, inSameDayAs: day)
        }.map { Double($0.amount) }.reduce(0, +)

        let expenseForDay = transactions.filter {
            $0.transaction == .expense && calendar.isDate($0.date, inSameDayAs: day)
        }.map { Double($0.amount) }.reduce(0, +)

        result.append((formatter.string(from: day), incomeForDay, expenseForDay))
    }

    return result
}

 

❇️ transactions는 ExpenseModel 타입의 배열로, 사용자의 모든 기록 데이터를 담고 있습니다.


🔍 핵심: filter 고차함수 분석

✳️ 이 부분이 핵심입니다

let incomeForDay = transactions.filter {
    $0.transaction == .income && calendar.isDate($0.date, inSameDayAs: day)
}.map { Double($0.amount) }.reduce(0, +)

 

💡 이 코드는 무슨 일을 할까?

  • transactions 배열 중에서
    • 수입 항목이면서
    • 날짜가 "현재 요일(day)"와 같은 것만 골라냄(filter)
  • 그리고 해당 항목들의 amount 값을
    • Double로 변환(map)
    • 합산(reduce)

📎 filter 전 vs 후 비교

🔸 filter 사용 전 (일반 반복문 방식)

var incomeForDay = 0.0
for item in transactions {
    if item.transaction == .income && calendar.isDate(item.date, inSameDayAs: day) {
        incomeForDay += Double(item.amount)
    }
}

 

  • 절차적 방식 (명확하지만 반복될수록 코드가 길어짐)
  • 수입이면서 해당 날짜와 같은 날인지 조건문으로 판별

 

🔹 filter 사용 후 (함수형 스타일)

let incomeForDay = transactions.filter {
    $0.transaction == .income && calendar.isDate($0.date, inSameDayAs: day)
}.map { Double($0.amount) }.reduce(0, +)

 

 

  • filter: 조건에 맞는 데이터만 추려냄
  • map: Int → Double 변환
  • reduce: 합계 구함
  • 한 줄로 간결하고 선언적 (무엇을 하는지 바로 드러남)

🧪 실제 예시로 이해해보기

transactions = [
    ExpenseModel(transaction: .income, amount: 1000, date: "2025-07-29"),
    ExpenseModel(transaction: .expense, amount: 500, date: "2025-07-29"),
    ExpenseModel(transaction: .income, amount: 2000, date: "2025-07-29"),
    ExpenseModel(transaction: .income, amount: 3000, date: "2025-07-28")
]

let day = "2025-07-29"

 

 

🔍 filter 적용 결과

// 수입 && 7/29
transactions.filter {
    $0.transaction == .income && calendar.isDate($0.date, inSameDayAs: day)
}

// 결과:
[
  ExpenseModel(transaction: .income, amount: 1000, date: "2025-07-29"),
  ExpenseModel(transaction: .income, amount: 2000, date: "2025-07-29")
]

 

✨ 마치며

이처럼 filter는 실무에서 매우 강력한 도구입니다.
조건에 따라 데이터를 추려야 할 때, map, reduce와 조합하면 훨씬 깔끔한 코드로 결과를 만들 수 있습니다.

특히 날짜 기반 통계를 처리하는 앱(가계부, 캘린더, 통계 등)에서 자주 쓰이니 꼭 익혀두세요!

 

728x90
LIST