Swift에서 컬렉션 정렬 및 필터링

안녕하세요, 여러분! 오늘은 Swift 개발하면서 정말 자주 쓰이는, 그렇지만 알고 보면 더 멋지게 활용할 수 있는 기능에 대해 함께 알아보려고 해요. 바로 컬렉션 정렬 및 필터링 이야기입니다! 데이터를 다루다 보면 원하는 순서대로 정렬하거나 특정 조건에 맞는 데이터만 쏙쏙 뽑아내야 할 때가 정말 많잖아요? 기본적인 정렬, 필터링은 이미 알고 계시겠지만, 오늘 저와 함께라면 더욱 효율적이고 다채로운 방법들을 배우실 수 있을 거예요. `sort`와 `filter` 함수만 써도 좋지만, Swift는 훨씬 더 강력한 기능들을 숨겨놓고 있거든요. 어떤 내용들을 다룰지 궁금하시다고요? 간단하게 맛보기로 말씀드리면 컬렉션 정렬 기초부터 시작해서 다양한 정렬 기준 활용하기, 그리고 컬렉션 필터링 기법까지 차근차근 알아볼 거고요, 마지막에는 고급 필터링 및 정렬 조합 기술까지 살짝 엿볼 거예요! 자, 그럼 저와 함께 Swift 컬렉션 정렬 및 필터링의 세계로 풍덩 빠져볼까요?

 

 

컬렉션 정렬 기초

Swift에서 컬렉션을 다루다 보면 정렬은 마치 숨 쉬는 것처럼 자연스러운 필수 과정이에요. 마치 요리할 때 재료 손질이 기본인 것처럼 말이죠! 자, 그럼 Swift의 세계에서 컬렉션 정렬이라는 마법 지팡이를 어떻게 휘두르는지, 그 기초부터 차근차근 알아볼까요?

sorted() 메서드를 사용한 기본 정렬

가장 기본적인 정렬 방법은 sorted() 메서드를 사용하는 거예요. sorted()는 컬렉션의 요소들을 비교하여 오름차순으로 정렬한 새로운 컬렉션을 반환한답니다. 예를 들어, [3, 1, 4, 1, 5, 9, 2, 6]처럼 뒤죽박죽 섞인 숫자 배열이 있다고 해봅시다. 이 배열에 sorted()를 적용하면 [1, 1, 2, 3, 4, 5, 6, 9] 와 같이 정렬된 새로운 배열을 얻을 수 있어요! 참 쉽죠?

다양한 타입의 데이터 정렬

하지만 세상 모든 데이터가 숫자처럼 단순하지는 않잖아요? 문자열, 날짜, 심지어 직접 정의한 구조체까지, 다양한 타입의 데이터를 정렬해야 할 때도 있어요. 이럴 때는 어떻게 해야 할까요? 바로 비교 로직을 직접 정의하는 거죠!

sorted(by:) 메서드를 사용한 커스텀 정렬

sorted(by:) 메서드는 클로저를 인자로 받아요. 이 클로저 안에서 두 요소를 비교하는 로직을 작성하면 된답니다. 예를 들어, 문자열 배열을 사전 역순으로 정렬하고 싶다고 해봅시다. 그럼 클로저 안에서 > 연산자를 사용하면 되겠죠? ["apple", "banana", "cherry"].sorted(by: { $0 > $1 }) 이렇게 말이에요. 결과는 ["cherry", "banana", "apple"]! 원하는 대로 착착 정렬되는 모습, 정말 신기하지 않나요?

비교 연산자를 활용한 간결한 정렬

sorted(by:) 메서드는 강력하지만, 코드가 조금 복잡해 보일 수도 있어요. 특히 정렬 기준이 단순한 경우에는 더욱 그렇죠. 그래서 Swift는 더 간결한 방법도 제공해요! 바로 <, >, <=, >=와 같은 비교 연산자를 직접 활용하는 거예요. Comparable 프로토콜을 준수하는 타입이라면 이 방법을 사용할 수 있답니다. 예를 들어, 숫자 배열을 내림차순으로 정렬하려면 [3, 1, 4, 1, 5, 9, 2, 6].sorted(by: >)처럼 간단하게 표현할 수 있어요. 정말 깔끔하죠?

컬렉션 정렬 활용 예시

자, 이제 컬렉션 정렬의 기본기를 다졌으니, 실제로 어떻게 활용할 수 있는지 몇 가지 예시를 살펴볼까요? 예를 들어, 사용자의 이름을 알파벳 순으로 정렬해서 표시해야 한다고 생각해 봅시다. users.sorted { $0.name < $1.name } 이렇게 한 줄이면 충분해요! 또는 상품 목록을 가격순으로 정렬해야 한다면? products.sorted { $0.price < $1.price } 이것도 역시 한 줄로 해결! 정말 간편하고 강력하지 않나요?

sorted()와 sort() 메서드의 차이점

여기서 잠깐! sorted() 메서드는 새로운 컬렉션을 반환한다는 점을 기억하세요! 원본 컬렉션은 변경되지 않고 그대로 유지된답니다. 만약 원본 컬렉션 자체를 정렬하고 싶다면 sort() 메서드를 사용해야 해요. sort() 메서드는 원본 컬렉션을 직접 수정한답니다. 둘의 차이점, 꼭 기억해 두세요!

지금까지 컬렉션 정렬의 기초를 살펴봤어요. 기본적인 sorted() 메서드부터, 다양한 타입에 대한 정렬, 그리고 sort() 메서드까지! 어때요, 이제 컬렉션 정렬 마법사가 된 기분인가요? 다음에는 더욱 다양하고 강력한 정렬 기법들을 알아볼 거예요. 기대해 주세요~!

 

다양한 정렬 기준 활용하기

이전에는 기본적인 정렬 방식에 대해 알아봤죠? 이번에는 좀 더 흥미로운 영역으로 들어가 볼게요! 바로 다양한 기준을 활용한 정렬 기법입니다! Swift는 정말 강력하고 유연한 정렬 기능을 제공하는데요, 단순히 오름차순이나 내림차순 정렬만으로는 우리의 복잡한 데이터를 완벽하게 다룰 수 없잖아요? ^^ 그래서 Swift는 다양한 조건으로 정렬 기준을 세울 수 있도록 sorted(by:) 메서드와 함께 클로저를 사용하는 방법을 제공한답니다.

쇼핑몰 앱 예시

자, 예를 들어 봅시다! 쇼핑몰 앱을 개발 중이라고 생각해 보세요. 상품 데이터를 가격 순으로 정렬하는 건 너무 쉽죠? 하지만 만약 가격이 같다면? 인기도 순으로 정렬하고 싶을 수도 있잖아요? 아니면 최신 등록 상품 순으로 정렬하고 싶을 수도 있고요! 이럴 때 어떻게 해야 할까요? 🤔

struct Product {
    let name: String
    let price: Double
    let popularity: Int
    let registrationDate: Date
}

위와 같이 상품 구조체가 있다고 가정해 볼게요. 이제 이 상품들을 다양한 기준으로 정렬해 보겠습니다!

가격 및 인기도 기준 정렬

먼저, 가격 오름차순으로 정렬하고, 가격이 같다면 인기도 내림차순으로 정렬해 볼까요?

let products: [Product] = [...] // 상품 데이터 배열

let sortedProducts = products.sorted { (p1, p2) -> Bool in
    if p1.price == p2.price {
        return p1.popularity > p2.popularity // 가격이 같으면 인기도 내림차순
    }
    return p1.price < p2.price // 가격 오름차순
}

보시는 것처럼 클로저 내부에서 if 문을 사용해서 여러 조건을 설정할 수 있어요! 가격이 같을 때만 인기도를 비교하도록 했죠? 정말 간단하지 않나요?!

가격, 인기도, 등록일 기준 정렬

이번에는 좀 더 복잡한 조건을 추가해 볼까요? 가격이 같고, 인기도 같다면 등록일 순으로 정렬해 보겠습니다!

let sortedProducts = products.sorted { (p1, p2) -> Bool in
    if p1.price == p2.price {
        if p1.popularity == p2.popularity {
            return p1.registrationDate < p2.registrationDate // 등록일 오름차순
        }
        return p1.popularity > p2.popularity // 인기도 내림차순
    }
    return p1.price < p2.price // 가격 오름차순
}

if 문을 중첩해서 사용하면 얼마든지 복잡한 조건을 추가할 수 있다는 것을 알 수 있겠죠? 😉 물론, 조건이 많아질수록 코드가 복잡해지기 때문에 적절한 수준에서 관리하는 것이 중요해요!

튜플 활용

튜플을 활용하면 코드를 좀 더 간결하게 만들 수도 있어요. 여러 정렬 기준을 튜플로 묶어서 반환하면 Swift가 알아서 순차적으로 비교해 준답니다. 신기하죠?!

let sortedProducts = products.sorted {
    return ($0.price, -$0.popularity, $0.registrationDate) < ($1.price, -$1.popularity, $1.registrationDate)
}

위 코드에서 -$0.popularity처럼 마이너스를 붙여서 인기도는 내림차순으로 정렬하도록 했어요. 정말 간단하고 효율적이지 않나요?! 👍

KeyPath 활용

KeyPath를 사용하면 더욱더 간결하고 명확하게 코드를 작성할 수 있습니다. 특히 정렬 기준이 단순한 프로퍼티 비교일 경우 매우 유용해요.

let sortedProductsByPrice = products.sorted(by: \.price) // 가격 오름차순

let sortedProductsByPopularity = products.sorted(by: \.popularity, ascending: false) // 인기도 내림차순

KeyPath를 사용하면 코드가 훨씬 깔끔해지고, 가독성도 좋아진다는 것을 알 수 있죠? 정렬 기준이 명확하게 드러나서 유지보수도 쉬워진답니다. 😊

자, 이제 다양한 정렬 기준을 활용하는 방법을 알아봤으니, 여러분의 데이터를 자유자재로 정렬해서 멋진 앱을 만들어 보세요! 다음에는 컬렉션 필터링 기법에 대해 알아볼 거예요! 기대해 주세요! 😄

 

컬렉션 필터링 기법

후~ 드디어 정렬 마치고 필터링으로 넘어왔네요! 정렬만큼이나 중요하고, 또 재밌는 부분이 바로 이 필터링이에요. 마치 옷장 정리하듯이, 필요한 자료만 쏙쏙 뽑아낼 수 있도록 도와주는 마법같은 기능이죠! 자, 그럼 Swift에서 제공하는 다양한 필터링 기법들을 하나씩 살펴볼까요? ^^

filter 메서드를 사용한 기본 필터링

Swift에서 컬렉션(Array, Set, Dictionary 등)을 필터링하는 가장 기본적인 방법은 filter 메서드를 사용하는 거예요. 이 메서드는 클로저(closure)를 인자로 받는데, 이 클로저는 각 요소에 대해 참(true) 또는 거짓(false)을 반환해야 해요. true를 반환하는 요소들만 모아서 새로운 컬렉션을 만들어주는 아주 똑똑한 친구랍니다!

예를 들어, 1부터 10까지의 숫자를 담은 배열에서 짝수만 뽑아내고 싶다고 해볼게요. filter 메서드를 사용하면 아래처럼 간단하게 구현할 수 있어요. 놀랍지 않나요?!

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let evenNumbers = numbers.filter { $0 % 2 == 0 }
print(evenNumbers) // [2, 4, 6, 8, 10] 출력!

여기서 $0은 클로저가 현재 처리하고 있는 요소를 나타내는 약칭이에요. $0 % 2 == 0은 현재 요소를 2로 나눈 나머지가 0인지, 즉 짝수인지 확인하는 조건이죠. 참 쉽죠~?

filter 메서드는 단순한 숫자 비교뿐만 아니라, 문자열, 객체 등 다양한 데이터 타입에도 적용할 수 있어요. 예를 들어, 사용자 정보를 담은 배열에서 특정 조건을 만족하는 사용자만 찾아낼 수도 있죠. 마치 마법같지 않나요? ✨

struct User {
    let name: String
    let age: Int
}

let users = [
    User(name: "Alice", age: 25),
    User(name: "Bob", age: 30),
    User(name: "Charlie", age: 22),
    User(name: "David", age: 28)
]

let usersOver25 = users.filter { $0.age > 25 }
print(usersOver25) // [User(name: "Bob", age: 30), User(name: "David", age: 28)] 출력!

여기서는 나이가 25세 이상인 사용자만 필터링했어요. 이처럼 filter 메서드는 원하는 조건에 맞는 요소만 쏙쏙 골라낼 수 있도록 도와주는 강력한 도구랍니다!

다중 조건 필터링

하지만, filter 메서드만으로는 복잡한 필터링 조건을 처리하기 어려울 수도 있어요. 예를 들어, 여러 조건을 동시에 만족하는 요소를 찾거나, 특정 범위에 속하는 요소를 찾는 경우에는 어떻게 해야 할까요? 🤔

걱정 마세요! Swift는 이런 경우를 위해 && (AND), || (OR) 연산자를 제공해요. 이 연산자들을 활용하면 여러 조건을 조합하여 더욱 정교한 필터링을 수행할 수 있죠. 마치 레고 블럭처럼 조립하는 재미가 쏠쏠해요!

let youngAndActiveUsers = users.filter { $0.age < 30 && $0.name.contains("a") }
print(youngAndActiveUsers) // [User(name: "Alice", age: 25), User(name: "Charlie", age: 22)]  출력!

이 코드는 나이가 30세 미만이고 이름에 "a"가 포함된 사용자만 필터링하는 예시예요. && 연산자를 사용하여 두 조건을 모두 만족하는 사용자만 추출했죠. 이처럼 &&, || 연산자를 적절히 활용하면 원하는 결과를 정확하게 얻을 수 있어요.

고차 함수와의 체이닝

더 나아가, filter 메서드는 고차 함수(Higher-order function)이기 때문에 다른 메서드와 함께 체이닝(chaining)하여 사용할 수도 있어요. 예를 들어, map 메서드와 함께 사용하면 필터링된 결과를 원하는 형태로 변환할 수 있죠. 마치 요리 레시피처럼 다양하게 조합해 볼 수 있어요! 🧑‍🍳

let namesOfYoungUsers = users.filter { $0.age < 30 }.map { $0.name }
print(namesOfYoungUsers) // ["Alice", "Charlie", "David"] 출력!

이 코드는 30세 미만 사용자의 이름만 추출하여 새로운 배열을 생성하는 예시예요. filter 메서드로 나이 조건에 맞는 사용자를 필터링하고, map 메서드로 이름만 추출했죠. 이처럼 filter 메서드는 다른 메서드와 조합하여 더욱 강력한 기능을 발휘할 수 있답니다.

자, 이제 Swift의 filter 메서드를 이용한 컬렉션 필터링 기법에 대해 감을 잡으셨나요? 처음에는 조금 어려워 보일 수 있지만, 몇 번 연습하다 보면 금방 익숙해질 거예요. 다음에는 더욱 고급 필터링 및 정렬 조합 기법에 대해 알아볼 테니 기대해주세요~! 😉

 

고급 필터링 및 정렬 조합

이제까지 컬렉션을 정렬하고 필터링하는 기본적인 방법들을 살펴봤어요. 그런데 실제 개발에서는 훨씬 복잡한 상황에 맞닥뜨리게 되는 경우가 많죠? 마치 레고 블록처럼 여러 조건을 조합해야 딱 원하는 결과를 얻을 수 있을 때가 많답니다. 이번에는 그런 고급 필터링 및 정렬 기법들을 함께 파헤쳐 보도록 할게요! 준비되셨나요~? ^^

쇼핑몰 앱 예시

자, 예를 들어 쇼핑몰 앱을 개발한다고 생각해 보세요. 사용자는 가격, 상품평, 인기도 등 다양한 기준으로 상품을 정렬하고 필터링하고 싶어 할 거예요. 단순히 가격만 낮은 순으로 정렬하는 기능으론 부족하겠죠?! 가격은 낮은 순으로 정렬하되, 상품평이 4점 이상인 상품만 보고 싶어 할 수도 있고, 특정 브랜드의 상품 중 인기도 순으로 상위 10개만 보고 싶어 할 수도 있잖아요? 이런 복합적인 요구를 충족시키려면 고급 필터링 및 정렬 기술이 필수랍니다!

Swift에서는 고차 함수(`higher-order function`)들을 조합해서 이런 복잡한 로직을 아주 우아하게(?) 구현할 수 있어요. filter, sorted, map 같은 함수들을 마치 마법의 주문처럼 엮어서 마음대로 데이터를 주무를 수 있다는 거죠! 자, 그럼 본격적으로 어떤 마법 주문들이 있는지 하나씩 살펴볼까요?

filter와 sorted 조합

먼저 filtersorted를 조합하는 방법을 알아볼게요. 가격이 10,000원 이하이고 상품평이 4.5점 이상인 상품만 뽑아서 가격 순으로 정렬한다고 해볼게요. 코드로는 이렇게 표현할 수 있어요.

let products = [
    // ... (상품 데이터)
]

let filteredAndSortedProducts = products
    .filter { $0.price <= 10000 && $0.rating >= 4.5 }
    .sorted { $0.price < $1.price }

참 쉽죠? filter로 조건에 맞는 상품만 걸러낸 다음, sorted로 가격 순으로 정렬했어요. 마치 체로 거르고 나서 순서대로 정리하는 것과 같아요. 이렇게 하면 원하는 상품만 쏙쏙 뽑아서 예쁘게 정렬된 결과를 얻을 수 있답니다.

filter, sorted, prefix 조합

이번에는 좀 더 복잡한 예시를 볼까요? 특정 카테고리의 상품 중 할인율이 높은 순으로 정렬하고, 그중 상위 5개만 표시하는 경우를 생각해 보세요. filter, sorted, prefix를 조합하면 간단하게 해결할 수 있어요!

let category = "의류"
let top5DiscountedProducts = products
    .filter { $0.category == category }
    .sorted { $0.discountRate > $1.discountRate }
    .prefix(5)

filter로 카테고리가 "의류"인 상품만 걸러내고, sorted로 할인율이 높은 순으로 정렬한 다음, prefix(5)로 상위 5개만 뽑아냈어요! 참 간편하죠?! 이처럼 고차 함수들을 조합하면 복잡한 로직도 몇 줄의 코드로 간결하게 표현할 수 있어요. 코드가 짧아지면 오류 발생 가능성도 줄어들고 유지 보수도 훨씬 쉬워진답니다. 일석이조, 아니 일석삼조의 효과죠!

map 활용

map 함수를 활용하면 정렬이나 필터링 전에 데이터를 변형할 수도 있어요. 예를 들어 상품 가격에 부가세를 더한 값을 기준으로 정렬하고 싶다면 어떻게 해야 할까요? map을 이용해서 상품 데이터를 변형한 후 정렬하면 된답니다.

let productsWithVAT = products.map { product -> Product in
    var productWithVAT = product
    productWithVAT.price = product.price * 1.1 // 부가세 10% 추가
    return productWithVAT
}

let sortedProductsWithVAT = productsWithVAT.sorted { $0.price < $1.price }

이처럼 map을 이용하면 정렬이나 필터링 전에 데이터를 원하는 형태로 바꿀 수 있어요. 마치 요리하기 전에 재료를 손질하는 것과 같은 과정이죠. 이렇게 데이터를 미리 가공하면 더욱 정확하고 효율적인 필터링과 정렬이 가능해진답니다.

다양한 고차 함수 조합

filter, sorted, map 이외에도 reduce, compactMap, flatMap 등 다양한 고차 함수들을 조합해서 무궁무진한 필터링과 정렬 로직을 만들 수 있어요! 마치 요리사처럼 다양한 재료와 조리법을 활용해서 맛있는 요리를 만드는 것과 같아요. 처음에는 조금 어려워 보일 수 있지만, 여러 가지 조합을 시도해 보면서 자신만의 레시피를 만들어보세요. Swift의 강력한 고차 함수들을 마스터하면 어떤 복잡한 데이터도 자유자재로 다룰 수 있게 될 거예요! 화이팅!

 

Swift로 컬렉션 다루는 재미, 좀 느껴보셨나요? 정렬과 필터링, 처음엔 어려워 보여도 막상 해보면 생각보다 간단하다는 걸 알게 되셨을 거예요. 기본적인 정렬부터 시작해서, 다양한 조건으로 컬렉션을 내 마음대로 쏙쏙 골라내는 기법까지! 정말 신기하지 않나요? 이제 여러분의 코드는 훨씬 더 깔끔하고 효율적으로 변신할 준비가 되었어요. 배운 내용을 토대로 여러분만의 멋진 코드를 만들어보고, Swift의 매력에 푹 빠져보세요! 앞으로의 즐거운 코딩 여정을 응원할게요! 더 궁금한 점이 있다면 언제든 질문해주세요. 함께 Swift 세계를 탐험해 봐요!

 

Leave a Comment