문제 )
[ ] Int 배열의 짝수번째 요소를 제거해서 반환하는 함수 a 를 작성해주세요.
- 테스트 입력: [1, 2, 3, 4, 5]
- 테스트 출력: [1, 3, 5]
배열을 입력 받아 짝수번째 요소를 제거하고 남은 요소를 반환하는 함수를 작성하는 간단한 문제이다
내가 작성한 코드보다 코드리뷰를 통해 확인한 다른 팀원분들의 방법이 더 효과적이고 해당 코드를 통해 새롭게 알게된 프로퍼티를 소개하려고 한다
아래는 내가 해결한 방식이다
1. enumerated()를 사용하여 (offset, element) 튜플 생성
2. filter를 이용하여 짝수 번째 요소를 제거
3. map을 사용하여 (offset, element) 튜플 중 element만 반환
enumerated() + filter + map
// Int 배열의 짝수번째 요소를 제거해서 반환하는 함수 a
func a(arr: [Int]) -> [Int] {
// 인덱스는 0부터 시작이므로 짝수번째 요소 제거는 offset이 홀수인 요소룰 제거해야 함
return arr.enumerated().filter{$0.offset % 2 == 0}.map{$0.element}
}
우선, Int형 배열을 입력받아 Array 타입의 인스턴스 메서드 enumerated()를 사용하여 (offset, element) 튜플을 리턴받는다
이때 offset은 인덱스 번호, element는 해당 offset에 존재하는 값을 뜻한다
인덱스는 0부터 시작하기 때문에 짝수 번째 요소를 제거하려면 offset이 홀수인 요소를 제거해야 한다
따라서, filter를 통해 offset이 2로 나누어 떨어지는, 즉, 짝수인 값만 남기고 이후, map으로 element만 남기게 되는 로직이다.
다음은 팀원분들께서 작성한 방법이다
1. indices + filter + map
func a(_ arr: [Int]) -> [Int] {
return arr.indices.filter { $0 % 2 == 0 }.map { arr[$0] }
}
indices는 배열의 유효한 인덱스 범위를 직접 가져올 수 있다
예를들어, indices를 출력해보면 아래와 같이 출력된다
let arr = [1, 2, 3, 4, 5]
print(arr.indices) // 출력: 0..<5
arr.indices를 사용해 배열의 인덱스 범위를 가져오고
filter를 사용하여 짝스 인덱스를 제거, map을 통해 인덱스로 배열에 접근하여 요소를 배열로 저장하는 방법이다
indices를 사용하는 방법에 대해 배울 수 있었다
2. enumerated() + compactMap + isMultiple(of:)
enumerated()를 이용하여 (index, value) 튜플 생성
index가 짝수인지 확인 후 짝수라면 value를 남기고, 아니라면 nil로 넘겨서 compactMap에서 필터링 되도록 구현되었다
filter를 따로 쓰지 않고 nil로 바꾸어 compactMap에서 nil 값을 무시하는 방법이 좋아보였다
func a(_ intArray: [Int]) -> [Int] {
return intArray.enumerated().compactMap { index, value in
index.isMultiple(of: 2) ? value : nil
}
}
https://developer.apple.com/documentation/swift/int/ismultiple(of:)
isMultiple(of:) | Apple Developer Documentation
Returns if this value is a multiple of the given value, and otherwise.
developer.apple.com
isMultiple(of:)은 self가 of로 들어온 값의 배수인지 아닌지를 Bool 타입으로 반환하는 인스턴스 메서드이다
예를 들어,
let number = 12
print(number.isMultiple(of: 3)) // true
12는 3의 배수이기에 true를 리턴한다
그렇다면 % 연산과 똑같은가?
어떤 수를 0으로 나눌 때 %는 에러가 발생하지만, isMultiple은 어떤 수가 0이 아니라면, false를 리턴한다
let zero = 0
let four = 4
let six = 6
//print(zero % 0 == 0) // Error: Division by zero
print(zero.isMultiple(of: 0)) // true
//print(six % 0 == 0) // Error: Division by zero
print(six.isMultiple(of: 0)) // false
print(four.isMultiple(of: 0)) // false
따라서, isMultiple을 사용하는게 예외처리가 편할 수 있다
3. (0..<arr.count) + filter + map
func a(_ arr: [Int]) -> [Int] {
(0..<arr.count).filter { $0 % 2 == 0 }.map { arr[$0] }
}
0..<arr.count를 이용하여 인덱스 범위를 생성하고
filter를 통해 짝수 인덱스만 필터링한다
이후 map으로 해당 인덱스의 값을 가져오는 방법이다
이 코드도 enumerated()를 사용하지 않고 인덱스만 받아오므로 불필요한 튜플을 만들지 않는다는 장점이 있었다
회고
이런 인덱스와 값이 같이 쓰이는 문제에서 항상 enumerated()만 생각하게 되었는데 다른 분들의 코드를 보니 더 효율적이고 다양한 방법이 있다는 것을 알게 되었다
enumerated()와 filter, map을 사용하게 되면 시간 복잡도 뿐만 아니라, 불필요한 튜플을 사용하므로 메모리도 비효율적일 것 같다
다른 분들의 효율적인 코드들을 종합해보면
indices + compactMap + isMultiple
func a(_ arr: [Int]) -> [Int] {
return arr.indices.compactMap { index in
index.isMultiple(of: 2) ? arr[index] : nil
}
}
위 방법이 제일 효율적일 것 같다는 생각이든다
compactMap을 통해 map + filter를 따로 사용하지 않고
enumerated() 대신 indices로 불필요한 튜플을 생성하지 않을 수 있다
'Today I Learn' 카테고리의 다른 글
RxSwift에서 observe(on:)으로도 UI 업데이트가 즉시 반영되지 않는 이유와 해결법 (1) | 2025.04.01 |
---|---|
Swift - 날짜 설정 DateFormmater VS Date.FormatStyle (0) | 2025.03.27 |
Today I Learn: @escaping 클로저 (0) | 2025.03.14 |
Today I Learn: Swift에서의 Copy On Write (COW) (0) | 2025.03.12 |
Today I Learn: Swift에서의 연결 리스트 (0) | 2025.03.11 |