티스토리 뷰

Swift

Swift ) prefix / suffix

Zedd0202 2021. 12. 1. 00:17
반응형

 

안녕하세요 :) Zedd입니다.

Array의 인스턴스 메소드로 prefix / suffix가 있잖아요!?

다같은 prefix / suffix가 아니고..파라미터에 따라 조금씩 다른데, 

그냥 썼다가 아주 큰일날뻔 했어서 ㅎㅎ.. 한번 쫙 살펴보려고 합니다.

 

# 들어가기전에

prefix / suffix 친구들은 Array의 인스턴스 메소드이지만, return 타입은 ArraySlice<Element> 입니다. 

func someMethod(_ arr: [Int]) {}
let arr = [1, 2, 3, 4].prefix(3)
someMethod(arr) // 🚨 Error!

[Int]의 prefix를 가져왔지만, [Int]가 나오지 않고 ArraySlice<Int>가 나왔기 때문에 위 코드는 컴파일 에러가 나게 됩니다.

func someMethod(_ arr: [Int]) {}
let arr = [1, 2, 3, 4].prefix(3)
someMethod(Array(arr)) // ✅

그래서 이렇게 Array로 한번 더 감싸주든가 해서 넘겨야합니다.

 

[prefix]

prefix메소드는 4가지 종류가 있습니다. 

prefix(_ maxLength: Int)

prefix(upTo end: Int)

prefix(through position: Int)

prefix(while predicate: (Element) -> Bool)

 

# prefix(_ maxLength: Int)

Collection에서 지정한 maxLength까지 하위 시퀀스를 리턴합니다. 

(maxLength는 0 이상이어야함)

let numbers = [1, 2, 3, 4, 5]
print(numbers.prefix(2))
// Prints "[1, 2]"
print(numbers.prefix(10))
// Prints "[1, 2, 3, 4, 5]"

array의 요소는 5개까지 밖에 없지만, 내가 prefix(10)을 한다고 해서 에러가 나는건 아닙니다. 

그래서 내가 배열의 prefix를 가져오고 싶다~ 하는 거의 모든 케이스는 이 메소드로 커버가 될거에요 ㅎㅎ

 

# prefix(upTo: Int)

upTo하면 보통 ~~까지라는 뜻이잖아요? 

prefix(upTo: Int)는 Collection의 시작부터 지정된 위치까지(포함하지 않음)의 하위 시퀀스를 반환합니다.

자 여기서부터 살짝 헷갈릴 수 있는데요. 

prefix(_ maxLength: Int)에서는 그냥 앞에 maxLength개 내놔!! 이런식이었다면..

prefix(upTo: Int)는 이 Argument가 Index를 의미한다고 보면 됩니다.

let numbers = [1, 2, 3, 4, 5]
print(numbers.prefix(upTo: 4))

자 이렇게 하면 numbers의 인덱스는 0, 1, 2, 3, 4입니다.

어 근데 내가 prefix(upTo: 4)를 요청했어. 

그럼 Collection의 시작부터 지정된 위치(포함하지 않음)의 하위시퀀스가 반환됩니다.

그러니까 

[인덱스 - Value] 

0 - 1

1 - 2

2 - 3

3 - 4

--

4 - 5 < 포함하지 않음! 

이렇게 되는거죠.

그래서 결과는 

let numbers = [1, 2, 3, 4, 5]
print(numbers.prefix(upTo: 4))
// [1, 2, 3, 4]

가 나오게 됩니다. 그냥 Index로 생각하시면 편합니다.

upTo네? 포함안하니까 4번째 Index 전까지? 4번째 Index가 5니까..5전까지 리턴되겠네..[1, 2, 3, 4]네.. 

아직도 이해가 안간다면 아래 예제를 봅시다. 

let numbers = [1, 2, 3, 4, 5]
print(numbers.prefix(upTo: numbers.startIndex))
// []

startIndex..즉 0일텐데, 시작(==Index 0) 부터 Index 0까지인데!!포함안해

그러니까 빈 배열([])이 나오는거죠. 

 

🚨 주의사항 🚨

아래 코드를 보겠습니다. 

let numbers = [1, 2, 3, 4, 5]

print(numbers.prefix(upTo: 10))
print(numbers.prefix(10))

하나는 upTo고 하나는 그냥 prefix네요. 

위 코드는 prefix(upTo:) 메소드때문에 crash를 발생시킵니다. 

Array index is out of range

이기 때문에..

10번째 Index 전까지 가져와야하는데, 해당 Index가 없으니 Array index is out of range 가 나는 것입니다!!!!

이거 때문에 살짝 큰일날뻔...ㅎ

그러니까 prefix(upTo:)를 사용할 땐 항상 주의하기!!!!!!

 

🔖 참고

prefix(upTo:)를 사용하는것은 subscript notation을 아래와 같이 사용하는 것과 동일합니다.

let numbers = [1, 2, 3, 4, 5]
print(numbers[..<4])
// [1, 2, 3, 4]

prefix(upTo:)이렇게 사용하는 것 보다 subscript notation이 더 선호되는 표기법이라고 해요.

(The subscript notation is preferred over prefix(upTo:))

 

# prefix(through: Int)

stride에도 through가 있으니...잘 아시겠지만, upTo는 Argument를 포함안했다면 through는 포함합니다.

let numbers = [1, 2, 3, 4, 5]
print(numbers.prefix(through: 4))
// [1, 2, 3, 4, 5]

[인덱스 - Value]

0 - 1

1 - 2

2 - 3

3 - 4

4 - 5 

upTo는 4로 넘기면 4번째 인덱스 전까지! 그러니까 [1, 2, 3, 4] 이렇게 나왔다면,

through는 포함하기 때문에 [1, 2, 3, 4, 5]가 나오게 됩니다.

let numbers = [1, 2, 3, 4, 5]
print(numbers.prefix(through: numbers.startIndex))
// [1]

바로 알겠죠!?

upTo와 똑같이 Index로 접근하기 때문에

let numbers = [1, 2, 3, 4, 5]

print(numbers.prefix(through: 10)) // 🚨 Fatal error: Array index is out of range
print(numbers.prefix(10))

반드시 Valid한 Index를 넣어야합니다. 

 

# prefix(while predicate: (Element) -> Bool)

다른 prefix는 그냥 숫자만 넣어주면 됐다면..이건 Closure가 있네요. 

간단합니다. 

요소를 포함해야하는 경우 - true

요소를 제외해야하는 경우 - false

predicate가 false를 반환하면 다시 호출되지 않음. 

만 기억하면 됩니다. 

 

예제로 봅시다. 

let numbers = [3, 1, 2, 5, 4]
print(numbers.prefix(while: { $0 >= 3 }))
// [3]

3보다 같거나 큰 수들에 대해 prefix를 호출했습니다.

첫번째 element의 3은 3보다 같거나 크니 true

두번째 element의 1은 3보다 작으므로 false

predicate가 false를 리턴했으므로 종료.

결과 : [3]

쉽죠..!? 

 

[suffix]

suffix메소드는 2가지 종류가 있습니다. 

suffix(_ maxLength: Int)

suffix(from start: Int)

 

# suffix(_ maxLength: Int)

prefix(_ maxLength:)와 완전히 똑같습니다.

(maxLength는 0이상 이어야 합니다.)

let numbers = [1, 2, 3, 4, 5]
print(numbers.suffix(2))
// Prints "[4, 5]"
print(numbers.suffix(10))
// Prints "[1, 2, 3, 4, 5]"

 

# suffix(from start: Int)

요것도 Index기반이라고 생각하면 됩니다. 

내가 start로 넘긴 지정된 위치에서 Collection 끝까지의 하위 시퀀스를 반환합니다.

let numbers = [1, 2, 3, 4, 5]
print(numbers.suffix(from: 3))
// [4, 5]

from: 3..그러니까 Index 3부터 Collection의 끝(== Index 4)을 리턴하니 

[4, 5]가 리턴되는거죠. (~부터니까 시작은 포함하면 됩니다.)

 

🚨 주의 사항🚨 

Index기반이기 때문에 역시나 반드시 Valid한 Index를 넣어줘야합니다.

let numbers = [1, 2, 3, 4, 5]
print(numbers.suffix(from: 6)) // 🚨 Fatal error: Range requires lowerBound <= upperBound

위와같은 에러가 나온 이유는 대충 짐작이 가시죠!?

from: 6.. 그러니까 Index 6부터 Collection의 끝(== Index 4)을 리턴해야하는데

Range가 [6...4] == lowerBound가 upperBound보다 큰 상황이니 에러를 내게 됩니다.

 

suffix(from start: Int) 역시 subscript notation을 더 선호하는데요. 

let numbers = [1, 2, 3, 4, 5]
print(numbers[3...])
// [4, 5]

suffix(from: 3)이라고 표기하는 것 보다 numbers[3...]이렇게 표기하는걸 더 선호한다는 거!

 

반응형

'Swift' 카테고리의 다른 글

Swift ) Sequence  (1) 2022.02.05
Literal  (0) 2022.01.23
Swift 5.5 ) Codable synthesis for enums with associated values  (0) 2021.11.18
WWDC 21 ) What‘s new in Swift  (3) 2021.06.11
Swift 5.4 Released!  (3) 2021.04.28