궁금한 내용을 검색해보세요!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
서근 개발노트
티스토리에 팔로잉
SWIFT/Grammar

Swift : 기초문법 [세트(SET)]

서근
QUOTE THE DAY

-
Written by SeogunSEOGUN

반응형

본 게시글은 yagom님의 Swift 프로그래밍 3판을 참고하여 작성되었습니다.

 

세트 SET

스위프트에서 컬렉션 타입인 세트(set)를 살펴보겠습니다.

 

세트는 말 그대로 공통적인 것들을 묶어놓은 것이라고 볼 수 있습니다. 배열과 반대로 순서가 중요하지 않고, 유일한 값들로 채우려고 할 때 세트가 유용합니다. 또, 세트는 집합으로 활용하기에 아주 좋은 타입입니다

 

세트는 Set 키워드와 타입 이름의 조합으로 써줍니다. 또, 배열과 마찬가지로 대괄호로 값들을 묶어 세트 타입임을 표현합니다. 배열과 달리 줄여서 표현할 수 있는 축약형 ( Array<Int>를 [int]로 축약할 수 있었던) 이 없습니다. let 키워드를 사용하여 상수로 선언하면 변경 불가능한 세트, var 키워드를 사용하여 변수로 선언해 주성 할 수 있습니다. 마찬가지로 isEmpty 프로퍼티를 통해 비어있는 세트 인지 확인할 수 있겠죠. 그리고 count 프로퍼티로 세트의 요소 개수를 확인할 수 있습니다.

 

세트(Set)는 두 가지 차이점이 있다는 점을 제외하면 배열(array)과 같은 값의 모음입니다.

  • 항목은 어떤 순서로도 저장되지 않습니다. 사실상 임의의 순서로 저장됩니다.
  • 한 세트에 항목이 두 번 나타날 수 없습니다. 즉, 중복이 안됩니다. 모든 항목은 고유해야 합니다.

다음과 같이 배열에서 직접 집합을 만들 수 있습니다.

let colors = Set(["red", "green", "blue"])
//print = blue, green, red

출력된 값을 보면 우리가 생성 한 순서와 일치하지 않는다는 것을 알 수 있습니다. 실제로 임의의 순서가 아니라 순서가 지정되지 않았을 입니다. Swift는 순서대로 표시하지 않습니다. 순서가 지정되지 않았기 때문에 배열에서와 같이 숫자 위치를 사용하여 집합에서 값을 읽을 수 없습니다.

 

세트에 중복 항목을 삽입하려고 하면 중복 항목이 무시됩니다.

let colors2 = Set(["red", "green", "blue", "red", "blue"])
//print = green, red, blue

세트의 기본 프로퍼티

let emptyIntSet:Set = []
print(emptyIntSet)
let emptyIntSet:Set = Set()
print(emptyIntSet)
var animal: Set<String> = ["dog", "cat", "monkey", "lion", "dog"]
// String 타입의 Set을 선언과 동시에 초기화를 합니다.

print(animal.isEmpty)
// animal이 비어있는지 여부를 확인합니다.

animal.insert("tiger")
// animal에 값을 한 개 추가합니다.

print(animal.count)
// Set animal이 가진 값의 수를 세지만, 중복되는 것은 제외합니다.

print(animal.remove("cat")
// 요소가 삭제되면 해당 값을, 삭제되지 않으면 nil을 반환합니다.

세트 역시 기본적으로 요소를 추가하거나, 삭제를 할 수 있도록 프로퍼티를 제공하고 있고, 또 그것들이 정상적으로 수행되었는지 판단할 수 있도록 하고 있습니다.

var someStrSet:Set = ["ab", "bc", "cd", "de"]
if let someVal = someStrSet.remove("cd") {
    print(someVal)
    print(someStrSet)
} else {
    print("cannot find element to remove")
}

//print
cd
["de", "ab", "bc"]

세트와 배열이 다른 이유는??

세트와 배열은 모두 Swift에서 중요하며, 그 차이점이 무엇인지 이해하면 주어진 상황에서 어떤 것을 선택할지 이해하는 데 도움이 됩니다. 세트와 배열은 모두 데이터 모음이므로 단일 변수 내에 여러 값을 보유합니다. 그러나  값을 유지하는 방법 이 중요합니다. 세트순서가 지정되지 않고 중복을 포함할 수 없는 반면 배열순서를 유지하고 중복 을 포함 할 있습니다.

 

이 두 가지 차이점은 작게 보일 수 있지만 부작용이 있습니다. 세트는 추가 한 순서대로 개체를 저장할 필요가 없기 때문에 대신 빠른 검색을 위해 최적화하는 임의의 순서로 개체를 저장할 수 있습니다. 따라서 "이 세트에 항목 X가 포함되어 있습니까?"라고 말하면 세트의 크기에 관계없이 순식간에 답변을 얻을 수 있습니다.

 

이에 비해 배열은 항목을 제공 한 순서대로 저장해야 합니다. 따라서 항목 X가 10,000개의 항목을 포함하는 배열에 존재하는지 확인하려면 Swift가 첫 번째 항목에서 시작하여 발견될 때까지 모든 단일 항목을 확인해야 합니다.

 

즉, 큰 차이점은 "이 항목이 있습니까?"라고 말하고 싶을 때 세트가 더 유용하다는 것을 의미합니다. 예를 들어, 단어가 사전에 나타나는지 확인하려면 세트를 사용해야 합니다. 중복이 없고 빠른 검색을 할 수 있습니다.

예시

var readings = Set([true, false, true, true])
var ratings = Set([1, 1, 1, 2, 2, 2])
//세트에는 고유한 항목이 포함되어 있어야 하므로 중복된 값들은 삭제됩니다.
let someStrSet:Set = ["ab","bc","cd","de","ab"]
print(someStrSet)  //bc, ab, de, cd

잘못된 예시

let earthquakeStrengths = Set(1, 1, 2, 2)
let staffReviews = Set([1, 2, 1, 2, 3])

세트의 선언 와 생성

// 빈 세트를 생성하는 방법
var names1: Set<String> = Set<String>()
var names2: Set<String> = []

// Array와 마찬가지로 대괄호를 사용한다.
var names3: Set<String> = ["서근", "미진", "철수", "포뇨", "소피아"]

// 타입 추론을 사용하면 컴파일러가 Set가 아닌 Array로 타입을 지정함
var numbers = [100, 200, 300]
print(type(of: numbers)) // Array<Int>

print(names1.isEmpty) // true
print(names3.isEmpty) // false
print(names3.count) // 5

만약 타입 추론을 사용하면 컴파일러가 Set가 아닌 Array로 타입을 지정해주기 때문에 만약 Set를 사용하려면 반드시 Set 타입을 지정해줘야 합니다.

 

또, 세트에 요소를 추가하고 싶다면 Insert(_:) 메서드를 사용합니다. 요소를 삭제하고 싶다면 remove(_:) 메서드를 사용하는데, 메서드를 사용하면 해당 요소가 삭제된 후 반환됩니다.

var names3: Set<String> = ["서근", "미진", "철수", "포뇨", "소피아"]

names3.insert("캘시퍼")
print(names3) // ["소피아", "철수", "서근", "캘시퍼", "미진", "포뇨"]

names3.remove("미진")
names3.remove("소피아")
print(names3) // ["캘시퍼", "철수", "서근", "포뇨"]

print(names3.remove("민지")) // nil

세트의 활용 - 집합 연산

세트는 자신 내부의 값들이 모두 유일함을 보장하므로, 집합 관계를 표현하고자 할 때 유용하게 쓰일 수 있으며, 두 세트의 교집합, 합집합 등을 연산하기에 매우 용이합니다. 또한 sorted()메서드를 통해 정렬된 배열을 반환해줄 수도 있습니다.

  • intersection - 교집합
  • symmetricDifference - 여집합
  • union - 합집합
  • subtracting - 차집합
let myFavoriteFruits: Set<String> = ["사과", "배", "포도", "메론", "수박"]
let yourFavoriteFruits: Set<String> = ["메론", "수박", "딸기", "참외", "자두"]

// 교집합
let intersectSet: Set<String> = myFavoriteFruits.intersection(yourFavoriteFruits)
print(intersectSet)
// ["메론", "수박"]

// 여집합
let symmetricDiffSet: Set<String> = myFavoriteFruits.symmetricDifference(yourFavoriteFruits)
print(symmetricDiffSet)
// ["사과", "배", "포도", "참외", "자두", "딸기"]

// 합집합
let unionSet: Set<String> = myFavoriteFruits.union(yourFavoriteFruits)
print(unionSet)
// ["자두", "메론", "사과", "포도", "참외", "수박", "배", "딸기"]

// 차집합
let subtracSet: Set<String> = myFavoriteFruits.subtracting(yourFavoriteFruits)
print(subtracSet)
// ["사과", "배", "포도"]

//정렬된 배열을 반환해줌
print(unionSet.sorted())
// ["딸기", "메론", "배", "사과", "수박", "자두", "참외", "포도"]

세트의 활용 - 포함관계 연산

세트는 포함 관계를 연산할 수 있는 메서드로 구현되어 있습니다.

let 광역시: Set<String> = ["대전", "대구", "부산", "인천", "울산", "광주"]

let 도: Set<String> = ["경기도", "강원도", "충북", "충남", "전북", "전남", "경북", "경남"]

let 한국: Set<String> = 광역시.union(도)

print(한국)
/* 
["전남", "경기도", "대구", "충남", "충북", 
"부산", "경북", "대전", "전북", "광주", "울산", "경남", "인천", "강원도"]
*/

print(광역시.isDisjoint(with: 도)) // 서로 베타적인가? true
print(광역시.isSubset(of: 한국)) // 광역시가 한국의 부분집합인가? true
print(한국.isSuperset(of: 광역시)) // 한국이 광역시의 전체집합인가? true
print(한국.isSuperset(of: 도)) // 한국이 도의 전체집합인가? true

 

Set TEST : 문제를 풀려면 이곳을 클릭해주세요.

 

읽어주셔서 감사합니다🤟

 

 


잘못된 내용이 있으면 언제든 피드백 부탁드립니다.


서근


위처럼 이미지 와 함께 댓글을 작성할 수 있습니다.