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가 어디서 변경된거지? 라는 의문(혹은 혼란)을 줄 수 있으므로 주의!
기존에 프로그래머스에서 코딩 테스트 문제를 풀어보고 있었는데, 모닝 스터디에서 사용할 플랫폼이 프로그래머스라길래 중복 문제를 피하고자 개인적으로는 LeetCode를 사용해보기로 했다.
푼 문제는 이 블로그에 정리해서 올리고 있었는데, 크롬 확장 프로그램으로 백준 허브와 LeetHub를 사용하면 푼 문제를 자동으로 깃헙에 푸쉬해줄 수 있다고 한다!
앞으로는 깃헙 레포지터리에서 관리해볼까 싶다.
코딩 테스트 연습 레포지터리 - Algorithms-exercises

입력값에서 공백을 제거하는 코드가 중복 사용되고 있어 따로 빼서 함수를 생성하였다.
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() // 입력값 공백 제거 함수 확장에 구현
}
→ 함수를 호출하여 활용하고 있다.

바로 return하면 되는 걸 굳이 switch문 안에서 돌리고 있었다..
return Menu(rawValue: menu)
→ 한 줄로 간소화하였다.
기존 코드
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 열거형에는 문자열만 저장하고, strike와 ball에 따른 분기 처리는 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는 뭔가??
trimPrefix는 trimmingPrefix와 동일하게 동작하지만, 원본 배열을 바꾸는 메서드이다! sort와 sorted 처럼.
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] -- 컬렉션의 처음 부분과 일치하지 않으면 배열을 변경하지 않음.
기존 코드
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
}
}