본문 바로가기
Swift 공식 가이드/Swift 3

Collection Types - Set

by 토끼찌짐 2017. 2. 11.

Apple 제공 Swift 프로그래밍 가이드(3.0.1)의 Collection Types 중 Set 부분을 공부하며 정리한 글입니다. 개인적인 생각도 조금 들어가있습니다.


들어가며

Set은 같은 타입의 값을, 중복되지 않게, 순서없이 저장하는 Collection Type.

저장순서를 알 필요없고, Collection 안의 값이 모두 유니크해야 할 때 Set을 사용하면 적절하다.

<note> Swift’s Set type is bridged to Foundation’s NSSet class.


Hash Values for Set Types

Set에 저장될 Type은 반드시 hashable 해야한다.

  • hashable 한 Type이란? : 그 Type이 hash value를 알려줄 수 있다

  • hash value 란? : a = b 일때 a.hashValue == b.hashValue 를 만족하는 Int value

Swift의 모든 기본 타입(String, Int, Double, Bool 등)은 default로 hashable 하다. 또한 Enumeration case value 역시 default로 hashable 하다. 즉 이런 타입들은 Set에 저장될 수 있고 Dictionary의 key 값이 될 수도 있다. Int나 Bool 타입이 Dictionary Key로 쓰일 수 있다는 점이 Objective-C와 비교가 된다.

자신이 만든 Custom Type을 Set에 저장하거나 Dictionary의 Key 타입으로 사용하고 싶다면 Hashable protocol 을 따르도록 구현해야 한다. 참고로 Hashable protocol은 Equatable protocol을 따르고 있으므로 == operator 구현도 해야한다.

Hashable protocol을 따르기 위해서는

  • hashValue 라는 프로퍼티의 getter 제공

  • == (equals operator) 구현 제공. 다음 조건을 만족할 수 있도록

    1. a == a (Reflexivity)

    2. a == b 는, 즉 b == a (Symmetry)

    3. a == b && b == c 는, 즉 a == c (Transitivity)


Set Type Syntax

Set<Element>으로 만든다. Element는 Set에 저장할 값의 타입이다.

참고로 Set은 Array와 다르게 shorthand form이 없다. (var intArray: [Int] 는 Int 타입을 저장하는 Array를 만들어주지만, 이와 비슷하게 var intSet: <Int> 를 시도해보면 컴파일 에러)


Creating and Initializing an Set

 // 1. Empty Set 생성
var letters = Set<character>()
print("letters is of type Set<character> with \(letters.count) items.")
// prints "letters is of type Set<character> with 0 items.”

letters.insert("a")
// letters now contains 1 value of type Character
letters = []
// letters is now an empty set, but is still of type Set<Character>

// 2.Array Literal 을 이용하여 Set 생성
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres has been initialized with three initial items
// var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"] 만 써도 String타입이 저장될 Set을 유추해준다.
// <주의> Set을 명시하지 않으면 favoriteGenres는 array가 된다.


Accessing and Modifying a Set

 // 1. Set 안에 몇 개의 Item이 있는지 체크하기 위해 -> count 프로퍼티
print("I have \(favoriteGenres.count) favorite music genres.")
// prints "I have 3 favorite music genres.”


// 2. Set 안이 비어있는지 체크하기 위해 -> isEmpty 프로퍼티
if favoriteGenres.isEmpty {
    print("As far as music goes, I'm not picky.")
}
else {
    print("I have particular music preferences.")
}
// prints "I have particular music preferences.”


// 3. Set 에 Item 추가를 위해 -> insert 메서드
favoriteGenres.insert("Jazz")
// favoriteGenres now contains 4 items


// 4. Set의 Item 제거를 위해 -> remove 메서드
// remove(Item) 메서드는 Item이 Set에 있었다면 지우고 그 Item을 반환하고
// Item이 Set에 없었다면 nil을 반환한다
// removeAll() 메서드도 있음
if let removedGenre = favoriteGenres.remove("Rock") {
    print("\(removedGenre)? I'm over it.")
}
else {
    print("I never much cared for that.")
}
// prints "Rock? I'm over it.”


// 5. 특정 Item이 Set 안에 들어있는지 체크하기 위해 -> contains 메서드
if favoriteGenres.contains("Funk") {
    print("I get up on the good foot.")
}
else {
    print("It's too funky in here.")
}
// prints "It's too funky in here.”


Iterating Over a Set

for genre in favoriteGenres {
    print("\(genre)")
}
// Classical
// Jazz
// Hip hop

// Set 안의 Item을 특정 순서로 순회하고 싶다면 sorted() 메서드를 사용
// Item을 < 연산자로 sorting 한 array가 반환됨
for genre in favoriteGenres.sorted() {
    print("\(genre)")
}
// Classical
// Hip hop
// Jazz


Performing Set Operations

<Fundamental Set Operations>

기본적인 Set operation 들을 효율적으로 수행하는 방법을 어떻게 제공하는지 알아보자.

a와 b는 각각 Set이다. 각 벤다이어그램 위에 표기된 메서드는 벤다이어그램의 초록색 부분에 해당하는 Item들로 구성된 새로운 Set을 생성하여 반환해준다. 자세한 설명은 생략한다.

let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]

oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]


<Set Membership and Equality>

a, b, c는 각각 Set이며 a는 b의 superset, b는 a의 subset, b와 c는 서로에게 disjoint한 관계이다.

  • “is equal” operator (==) : 두 Set의 내용이 전부 동일 (Item의 type, count, value 모두)

  • isSubset(of:) : subset인지를 판별

  • isSuperset(of:) : superset인지를 판별

  • isStrictSubset(of:) : subset이면서, subset!=superset

  • isStrictSuperset(of:) : superset이면서, subset!=superset

  • isDisjoint(with:) : 두 Set 간의 교집합이 없음

let houseAnimals: Set = ["🐶", "🐱"]
let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
let cityAnimals: Set = ["🐦", "🐭"]

houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true


// 추가설명
let myAnimals: Set = ["🐮", "🐔"]
let myFriendAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]

myAnimals.isStrictSubset(of: farmAnimals)
// true
myFriendAnimals.isStrictSubset(of: farmAnimals)
// false



'Swift 공식 가이드 > Swift 3' 카테고리의 다른 글

Control Flow  (0) 2017.02.15
Collection Types - Dictionary  (0) 2017.02.11
Collection Types - Array  (0) 2017.02.11
Strings and Characters  (2) 2017.02.05
Basic Operators  (0) 2017.02.05