[내일배움캠프] 260115 TIL

Bambu·2026년 1월 15일

내배캠 TIL

목록 보기
20/52

1. 모닝 스터디

1) 고차함수에서의 외부 변수 변경

프로그래머스 - 배열 조각하기

func solution(_ arr:[Int], _ query:[Int]) -> [Int] {
    
    var result = arr

    query.enumerated().forEach {
        if $0.offset % 2 == 0 {
            result = result[...$0.element].map { Int($0) }
        } else {
            result = result[$0.element...].map { Int($0) }
        }
    }
    
    return result
}

forEach문 안에서 외부 변수인 result를 변경시키고 있음

⇒ 고차함수는 보통 용도에 맞게 구현되어 있음
→ 고차함수 내에서 용도와 다르게 사용된다면 코드를 읽는 사람에게 혼란을 야기할 수 있음

forEach 요소별로 '동작'하게 해야하는데 외부 변수를 변경시킨다면 추후 result가 어디서 변경된거지? 라는 의문(혹은 혼란)을 줄 수 있으므로 주의!

2. 코테 연습하기

기존에 프로그래머스에서 코딩 테스트 문제를 풀어보고 있었는데, 모닝 스터디에서 사용할 플랫폼이 프로그래머스라길래 중복 문제를 피하고자 개인적으로는 LeetCode를 사용해보기로 했다.

푼 문제는 이 블로그에 정리해서 올리고 있었는데, 크롬 확장 프로그램으로 백준 허브LeetHub를 사용하면 푼 문제를 자동으로 깃헙에 푸쉬해줄 수 있다고 한다!

앞으로는 깃헙 레포지터리에서 관리해볼까 싶다.

코딩 테스트 연습 레포지터리 - Algorithms-exercises

3. 프로그래밍 심화 주차 - 야구 게임

1) 코드 리뷰

가. 중복 코드 함수화

입력값에서 공백을 제거하는 코드가 중복 사용되고 있어 따로 빼서 함수를 생성하였다.

extension BaseballGame {
    // 입력값 공백 제거
    func inputWithNoSpace() -> String {
        var input = readLine() ?? ""
        input = input.replacingOccurrences(of: " ", with: "")
        return input
    }
}

게임의 핵심 기능은 아니기 때문에 확장으로 빼서 구현하였다.

        var menu = inputWithNoSpace()
        
        // 입력문 유효성 검사
        while !condition.contains(menu) {
            print(GameMessage.invalidInput, GameMessage.selectMenuExample)
            menu = inputWithNoSpace() // 입력값 공백 제거 함수 확장에 구현
        }

→ 함수를 호출하여 활용하고 있다.

나. 열거형을 통한 switch문 간소화

바로 return하면 되는 걸 굳이 switch문 안에서 돌리고 있었다..

return Menu(rawValue: menu)

→ 한 줄로 간소화하였다.

2) 리팩토링

가. 정답 확인 함수 문자열 출력부 수정

기존 코드

enum GameMessage {
	...
    
    static func getHint(for strike: Int, _ ball: Int) -> String {
    	return strike == 3 ? "정답!" : 
        	strike == 0 && ball == 0 ? : "Nothing" :
            "\(strike) 스트라이크 \(ball) 볼입니다!"
    }
}
class BaseballGame {
	...
    
    func checkAnswer() {
    ...
    print(GameMessage.getHint(fopr: hint.strike, hint.ball))
    if hint.strike == 3 { isCorrect = true }
}

→ 아무리 생각해도 정답인지 아닌지 판단은 정답 확인 함수 내부에서 작동해야할 것 같아 수정했다.

변경 코드

enum GameMessage {
	...
    
    static let correct = "정답"
    static let nothing = "Nohting"
    
    static func getHint(for strike: Int, _ ball: Int) -> String {
    	return "\(strike) 스트라이크 \(ball) 볼입니다ㅣ!"
    }
    ...
}

class BaseballGame {
	...
    
    func checkAnswer() {
    ...
    
    	if hint.strike == 3 {
    		isCorrect = true
        	print(GameMessage.correct)
    	} else if hint.strike == 0 && hint.ball == 0 {
    		print(GameMessage.nothing)
    	} else {
    		print(GameMessage.getHint(for: hint.strike, hint.ball))
    	}
	}
}

GameMessage 열거형에는 문자열만 저장하고, strikeball에 따른 분기 처리는 checkAnswer() 내부에서 하도록 수정하였다.

나. 정답 생성 함수

기존 코드

    func setAnswer() {
        // 초기화
        isCorrect = false
        answer = []
        
        for _ in 0...2 {
            // 정답 첫 번째 숫자일 경우
            if answer.isEmpty {
                let num = Int.random(in: 1...9)
                answer.append(num)
            } else {
                var num = Int.random(in: 0...9)
                // 정답에 포함되어있다면 num 재생성
                while answer.contains(num) {
                    num = Int.random(in: 0...9)
                }
                answer.append(num)
            }
        }
        debugPrint("정답: \(answer)")
    }

→ 튜터님께서 shuffle() 메서드를 활용해보라 알려주셔서 적용해보았다.

변경 코드

func setAnswer() {
	...
    
    var num = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // 정답 숫자 후보
    num.shuffle() // 숫자 배열 섞기
    answer = num[0] != 0 ? Array(num[0...2]) : Array(num[1...3]) // 첫 번째 숫자가 0일 경우 예외 처리
}

→ 반복문을 없애고 훨씬 간결하게 코드를 작성할 수 있었다!

func setAnswer() -> [Int] {
	return Array((0...9).shuffled()
    	.trimmingPrefix(while: { $0 == 0 })
        .prefix(3))
}

⇒ 메서드를 활용하여 변수 선언 없이 더 간결하게 만들 수 있다.

trimmingPrefix 메서드
우선 trimmingPrefix(while:)trimmingPrefix(_:)를 살펴보자.

let a = [0, 1, 2, 3, 4, 5]

a.trimmingPrefix(while { $0 == 0 } )
// [1, 2, 3, 4, 5]: Array<Int>.SubSequence 출력
a.trimmingPrefix([0, 1, 2])
// [3, 4, 5]: Array<Int>.SubSequence 출력
  • trimmingPrefix(while:) : while 조건과 일치하는 컬렉션의 앞부분을 제거
  • trimmingPrefix(_:) : 괄호 안의 컬렉션과 완전히 일치하는 컬렉션의 앞부분을 제거
a.trimmingPrefix([1, 2])
// [0, 1, 2, 3, 4, 5]: Array<Int>.Subsequenece 출력

a 배열은 [0, 1, 2]로 시작하므로 잘리지 않음
→ 타입은 Array<Int>.SubSequence

그럼 trimPrefix는 뭔가??
trimPrefixtrimmingPrefix와 동일하게 동작하지만, 원본 배열을 바꾸는 메서드이다! sortsorted 처럼.

var a = [0, 1, 2, 3, 4, 5]

a.trimPrefix(while { $0 == 0 })
// [1, 2, 3, 4, 5]: [Int] -- 0 삭제
a.trimPrefix([1, 2])
// [3, 4, 5]: [Int] -- [1, 2] 삭제
a.trimPrefix([0])
// [3, 4, 5]: [Int] -- 컬렉션의 처음 부분과 일치하지 않으면 배열을 변경하지 않음.

다. forEach -> for문으로 변경

기존 코드

    func checkAnswer() {
        // 힌트 초기화
        var hint: (strike: Int, ball: Int) = (0, 0)
        // 힌트 설정(스트라이크, 볼)
        userAnswer.enumerated().forEach {
            if answer[$0.offset] == $0.element {
                hint.strike += 1
            } else if answer.contains($0.element) {
                hint.ball += 1
            }
        }

→ 모닝 스터디에서 얘기 들었던 고차함수 내에서의 변수값 변경을 여기서도 하고 있어서 for문으로 전환하려 한다.

변경 코드

        for (i, element) in userAnswer.enumerated(){
            if answer[i] == element {
                hint.strike += 1
            } else if answer.contains(element) {
                hint.ball += 1
            }
        }
profile
안녕하세요, iOS 개발을 공부하고 있는 Bambu입니다. (프로필: Swifticons)

0개의 댓글