Today I Learn

Today I Learn - 배열의 짝수 번째 요소를 제거하는 다양한 방법

Goniii 2025. 3. 20. 15:09

 

문제 )

[ ] 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로 불필요한 튜플을 생성하지 않을 수 있다