[Swift] Filter 함수 구현해 보기
개요
지난 시간에는 Map
, Reduce
, Filter
함수 중 Map
함수를 구현해 봤습니다. 이번 시간에는 Filter
함수를 구현해 보도록 하겠습니다.
이 포스트를 제대로 이해하기 위해서는 Closure와 Generic에 대한 이해가 선행돼야 합니다. 만약 익숙하지 않으시다면 Swift 공식문서의 Closure(영어, 한국어)와 Generic(영어, 한국어) 섹션의 정독을 권해드립니다.
Filter 함수의 동작
filter
함수는 이름에서 유추해 볼 수 있다시피 주어진 콜렉션에서 특정 조건의 원소만 걸러서 반환해주는 함수입니다. 예를 들어, 입력이 다음과 같고
let sampleFiles = ["HowTo.md","HelloiPhone.swift","HelloSwift.swift","HelloProgrammers.swift","README.md"]
이 콜렉션 중 확장자가 md인 파일만 뽑아내고 싶은 경우 다음과 같이 filter
함수를 사용할 수 있습니다.
let filteredFiles = sampleFiles.filter { $0.hasSuffix(".md") }
print("Filtered Files : \(filteredFiles)")
위 코드를 실행한 결과는 다음과 같습니다.
Filtered Files : ["HowTo.md", "README.md"]
그럼 지금부터 위 예제로부터 filter
함수를 어떻게 구현할 수 있는지 알아보도록 하겠습니다.
Filter 함수의 구현
앞의 예제에서는 콜렉션에서 확장자가 md인 파일만 뽑아냈습니다. 같은 기능을 수행하는 함수를 다음과 같이 만들 수 있습니다.
func getMDFiles(files: [String]) -> [String] {
var result = [String]()
for file in files {
if file.hasSuffix(".md") {
result.append(file)
}
}
return result
}
이 함수에서 핵심은 if file.hasSuffix(".md")
이 부분이라고 할 수 있습니다. 이 조건을 만족하는 원소만 수집해서 반환하게 되는 것이죠. 그래서 이 부분을 함수화 시키면 입력하는 함수의 조건대로 필터링을 수행하는 함수를 만들 수 있을 것 입니다.
Generic
을 이용해 customFilter
함수를 만들면 다음과 같습니다.
func customFilter<T>(xs: [T], check: (T) -> Bool) -> [T] {
var result = [T]()
for x in xs {
if check(x) {
result.append(x)
}
}
return result
}
콜렉션을 입력으로 넣고 추출할 원소의 조건을 함수로 check()
에 넣어줍니다. 그러면 입력한 함수에 해당하는 조건을 만족하는 원소만을 추출해 반환해 줍니다.
let filteredFiles = sampleFiles.filter { $0.hasSuffix(".md") }
print("Filtered Files : \(filteredFiles)")
위 함수를 실행하면 앞서와 동일한 결과를 얻을 수 있습니다.
CustomFilter Result : ["HowTo.md", "README.md"]
지난 번과 마찬가지로 저희가 구현한 customFilter
함수를 Array
에 추가해 Swift에서 기본으로 제공하는 filter
함수와 같이 동작하도록 만들기 위해 다음과 같이 Array
클래스에 customFilter
를 확장해 추가해 보도록 하겠습니다.
extension Array {
func customFilter(check: (Element) -> Bool) -> [Element] {
var result = [Element]()
for x in self {
if check(x) {
result.append(x)
}
}
return result
}
}
이제 Array
에서 저희가 구현한 customFilter
를 사용할 수 있습니다. 😎
Filter 함수와 CustomFilter 함수의 동작
이제 Swift에서 기본적으로 제공해주는 filter
의 동작과 저희가 구현한 customFilter
의 동작을 비교해 보도록 하겠습니다.
[소스코드]
let sampleFiles = ["HowTo.md","HelloiPhone.swift","HelloSwift.swift",
"HelloProgrammers.swift","README.md"]
let filterResult1 = sampleFiles.filter{ $0.hasSuffix(".md") }
let customFilterResult1 = sampleFiles.customFilter{ $0.hasSuffix(".md") }
let filterResult2 = sampleFiles.filter{ $0.hasPrefix("Hello") }
let customFilterResult2 = sampleFiles.customFilter{ $0.hasPrefix("Hello") }
let filterResult3 = sampleFiles.filter{ $0.contains("README") }
let customFilterResult3 = sampleFiles.customFilter{ $0.contains("README") }
print("Filter #1 : \(filterResult1)")
print("customFilterResult #1 : \(customFilterResult1)")
print("======================")
print("Filter #2 : \(filterResult2)")
print("customFilterResult #2 : \(customFilterResult2)")
print("======================")
print("Filter #3 : \(filterResult3)")
print("customFilterResult #3 : \(customFilterResult3)")
[실행결과]
Filter #1 : ["HowTo.md", "README.md"]
customFilterResult #1 : ["HowTo.md", "README.md"]
======================
Filter #2 : ["HelloiPhone.swift", "HelloSwift.swift", "HelloProgrammers.swift"]
customFilterResult #2 : ["HelloiPhone.swift", "HelloSwift.swift", "HelloProgrammers.swift"]
======================
Filter #3 : ["README.md"]
customFilterResult #3 : ["README.md"]
Swift에서 제공하는 filter
함수와 저희가 만든 customFilter
함수가 동일하게 동작하는 것을 확인할 수 있습니다.
결론
filter
함수 역시 쉽게 구현할 수 있다는 것을 확인 할 수 있었습니다. 다음 포스트에서는 map
, reduce
, filter
함수중 남은 reduce
함수를 직접 구현해 보겠습니다. 😄