스위프트에서 Closures는 다른 언어에서의 Lambda와 비슷하다.
let closuresTest:(Int) -> (String) = { _ in
return "Hello, Polytech!"
}
let result = closuresTest(0)
print(result)
결과 : Hello, Polytech!
이유는 모르겠지만... 인풋 없이 하고 싶은데 계속 에러가 난다... 이런식으로라도 그냥 의미 없게라도 넣어야 작동한다...
let closuresTest:(Bool) -> (String) = { _ in
return "Hello, Polytech!"
}
let result = closuresTest(false) // () 안의 값은 아무 의미도 없다... 그냥 arguments를 지정하지 않을 경우 누락되었다고 에러가 발생해서 형식상 넣어준 것이다.
print(result)
결과 : Hello, Polytech!
sort에 closures를 적용시켜보자.
Swift의 내장 함수 sort는 기본적으로 오름차순 정렬만 된다. 내림차순을 하려면 어떻게 해야할까?
1. sort 후 reverse 하기
var testArray:Array<Int> = [4, 6, 8, 1, 3]
print(testArray)
결과 : [4, 6, 8, 1, 3]
var testArray = [4, 6, 8, 1, 3]
testArray.sort()
print(testArray)
결과 : [1, 3, 4, 6, 8]
var testArray = [4, 6, 8, 1, 3]
testArray.sort()
testArray.reverse()
print(testArray)
결과 : [8, 6, 4, 3, 1]
하지만 이렇게 정렬하는 것은 불필요한 코드가 생기고 불필요한 계산이 추가된다.
2. 정렬을 내가 정의한 함수의 알고리즘으로 작동시키기
insertion sort는 배열에서 2개의 숫자를 비교한 뒤 Boolean 값이 True인 것만 반환하여 정렬한다.
즉, 기본이 오름차순 정렬인 스위프트에서 정렬을 시작하면, 배열의 index 0, index 1 2개의 값이 sort 함수로 들어가고, 그 sort 함수는 이 2개의 값을 비교한다.
[5, 3, 7] 이라는 배열이 있다. 이 때 index 0의 값을 잠시 number1이라 하자. 마찬가지로, index 1의 값을 잠시 number2라 하자.
그러면 number1(=5) > number2(=3)이기 때문에 return 값으로 number1 < number2를 반환하고 싶지만 결과가 false가 된다.
따라서 이번에는 다시 두 수의 순서를 바꾸어 비교를 해본다. 그러면 number(=3) < number2(=5) 이므로 true가 된다. 따라서, index 0과 index 1은 순서가 바뀌게 된다. 즉, 이제 [3, 5, 7]이 된거다.
그러면 또 다시 index 0과 index 1이 뒤바뀐 [3, 5, 7]을 가지고 비교를 한다. 이번에는 새 index 1의 값을 잠시 number1이라 하고, index 2의 값을 잠시 number2라 하자. 그러면 number1(=5) < number2(=7)이기 때문에 return 값으로 number1 < number가 바로 true가 되고 이를 그대로 반환한다. 즉, 최종적으로 [3, 5, 7]로 정렬이 되는 것이다. 배열의 길이가 짧든 길든 이런 과정을 배열의 마지막까지 반복해서 정렬을 한다.
따라서, 이 때 sort가 반환하는 return되는 Bool 값의 True 값을 바꾸면 Ascending Sort를 Descending Sort로 바꿀 수 있는 것이다. 따라서 함수는 (Int, Int) -> Bool 형식이 되어야 한다.
func sortASC(num1: Int, num2: Int) -> Bool {
return num1 < num2
}
즉, 이런 형태의 Bool 로직을 반대로 바꿔주면 된다.
func sortDESC(num1: Int, num2: Int) -> Bool {
return num1 > num2
}
해설 : 앞에 오는 숫자가 뒤에 오는 숫자보다 더 크면 true고 이를 return하라는 것이다. 즉, 큰수 -> 작은수 순으로 정렬된다.
그리고 sort의 Bool판단 로직을 내가 정의한 함수로 작동시킨다.
var numbers = [4, 6, 8, 1, 3]
func sortDESC(num1: Int, num2: Int) -> Bool {
return num1 > num2
}
numbers.sort(by: sortDESC)
결과 : [8, 6, 4, 3, 1]
마찬가지로 문자열 정렬일 경우는 (String, String) -> Bool 형식이 되어야 한다.
var name = ["Bella", "Elin", "Matilda", "Raina", "Kate", "Alice"]
func sortDESC(s1: String, s2: String) -> Bool {
return s1 > s2
}
name.sort(by: sortDESC(s1:s2:))
결과 : ["Raina", "Matilda", "Kate", "Elin", "Bella", "Alice"]
3. Closures 익명함수를 써서 위 코드를 줄여보자.
다른 언어에서 Lambda와 비슷한 역할을 하는 것이 스위프트에서는 Closures라는 것이 있다.
func sortDESC(num1: Int, num2: Int) -> Bool {
return num1 > num2
}
// 에서 함수의 이름을 지우고 함수 전체를 {}로 감싼다.
// 즉, 함수 이름을 지운 다음 그 자리(num1: Int 앞부분)에 { 를 입력하고
// 함수 전체를 {}로 감쌌기 때문에 Bool 뒤에 따로 함수의 로직만 분리해두었던 { 의 시작 부분은 in으로 바꿔준다.
// 최종 형태는 다음과 같다.
{(num1: Int, num2: Int) -> Bool in
return num1 > num2
}
// 이제 이것을 함수의 이름을 넣었던 자리에 익명으로 함수 자체를 넣어버리자. 따라서
numbers.sort(by: sortDESC)
// 는 이제 이렇게 바꿔 쓸 수 있다.
numbers.sort(by: {(num1: Int, num2: Int) -> Bool in
return num1 > num2
})
결과 : [8, 6, 4, 3, 1]
4. 위 익명함수를 줄여보자. (Closures 간략하게 줄이기)
스위프트에서는 인풋 파라미터의 자료형을 명확히 지정하지 않아도 스스로 유추가 가능하다. 따라서 위 로직은 더 짧게 바꿀 수 있다. 아예 num1, num2도 n1, n2로 줄여보자.
var numbers = [4, 6, 8, 1, 3]
numbers.sort(by: {n1, n2 -> Bool in return n1 > n2})
print(numbers)
결과 : [8, 6, 4, 3, 1]
5. 이 익명함수를 더 줄요보자. (Closuers 더 간략하게 줄이기)
스위프트의 closures는 파라미터를 $0, $1, $2, ... 로 축약할 수 있다. 따라서 위 코드는 다음과 같이 줄일 수 있다. 심지어 위에서는 자료형을 생략했지만 이제 인풋 파라미터를 명시하는 것 조차 생략할 수 있다.
var numbers = [4, 6, 8, 1, 3]
numbers.sort(by: {$0 > $1})
print(numbers)
결과 : [8, 6, 4, 3, 1]
cf. 정렬을 삼항 연산자와 Closures를 사용하기(오름차순)
data.sort (by: {sortedColumn.sorting == .ascending ? $0[sortedColumn.column] < $1[sortedColumn.column] : $0[sortedColumn.column] > $1[sortedColumn.column]})
위 수식을 아래와 같이 사용할 수도 있다.
data.sort {
let ascending = $0[sortedColumn.column] < $1[sortedColumn.column]
return sortedColumn.sorting == .ascending ? ascending : !ascending // ? true -> 위에 let ascending : false -> ! 붙어서 < 가 반대로 뒤집혀 > 가 되니 descending으로 작동
}
사실... 파라미터 축약 마저도 생략하고 써도 내장함수에 정의되어 있어서 정렬된다...
var numbers = [4, 6, 8, 1, 3]
numbers.sort() // 결과 : [1, 3, 4, 6, 8], inplace=true
numbers.sort(by: <) // 결과 : [1, 3, 4, 6, 8], inplace=true
numbers.sort(by: >) // 결과 : [8, 6, 4, 3, 1], inplace=true
numbers.sorted() // 결과 : [1, 3, 4, 6, 8], inplace=false
numbers.sorted(by: <) // 결과 : [1, 3, 4, 6, 8], inplace=false
numbers.sorted(by: >) // 결과 : [8, 6, 4, 3, 1], inplace=false
'개발자 > Swift' 카테고리의 다른 글
Swift 관련 사이트 및 정보 모음 (0) | 2021.02.02 |
---|---|
Swift (스위프트) 3항 연산자 (0) | 2020.06.20 |
Swift (스위프트) Firebase 로그인 연동 (0) | 2020.06.03 |
Swift (스위프트) 네이버 OpenAPI 이용해 검색하기 (0) | 2020.05.19 |
Swift (스위프트) Annotation (0) | 2020.05.19 |