Dictionary

딕셔너리는 배열, 튜플과 달리 순서없는 데이터의 모음이다. 단, 데이터는 '키-값'의 한쌍으로 구분된다. 

따라서 딕셔너리의 선언은 키의 자료형과 값의 자료형을 명시하여 선언한다.

var 딕셔너리이름 : Dictionary< 키자료형 : 값자료형 > = [키1:값, 키2:값, 키3:값, ... ]

값은 중복할 수 있으나, 키는 값을 호출하는데에 사용하기에 중첩할 수 없다.

//선언 및 생성
var dic:Dictionary<String:String> = ["red":"빨강","blue":"파랑","green":"파랑","yellow":"노랑"]    
//키는 중첩되면 안된다.
print(dic)  //딕셔너리는 순서가 랜덤하게 출력된다.

딕셔너리의 출력 결과를 보면 순서없이 출력되는 모습을 볼 수 있다.


선언 및 초기화

선언 및 초기화에는 여러가지 방법들이 있다.

//선언 및 비어있는 형태로 생성
var dic2:[String:Int] = [:]     //String형태의 키, Int형태의 값으로 생성.
print(dic2)

var dic3:Dictionary<Int,Int> = [:]  //Int형태의 키, Int형태의 값으로 생성.
print(dic3)

dic3 = [3:100,7:200,10:5]   //키-값 대입하여 초기화
print(dic3)

var dic4 = [String:String]()    //비어있는 형태로 생성
print(dic4)

var dic5 = Dictionary<Int,String>() //비어있는 형태로 생성
print(dic5)


원소 호출

딕셔너리의 원소(값)의 호출방법이다. 키를 이용하여 호출 및 접근한다.

//원소호출
//print(dic[0]) 딕셔너리는 순서가 없다.
print("dic[\"red\"]:",dic["red"]!)  //옵셔널로 반환된다. 값이 없을수도 있기에
print("dic[\"pink\"]:",dic["pink"])  //없는 키를 출력시 nil이 출력된다.(옵셔널)

기본적으로 출력 형태는 옵셔널로 출력된다. 키와 값의 존재유무가 확실하지 않기 때문이다.


추가 및 대입

딕셔너리는 튜플과 달리 원소의 추가가 가능하며, 기존의 키에 해당하는 값의 변경 또한 가능하다.

//대입 및 추가
dic["yellow"] = "누렁이"   //기존의 키에 새로운 값 대입
dic["orange"] = "주황"    //'키-값'의 추가도 가능하다.
print(dic)


삭제

대입 및 추가와 같이 키를 사용하여 값을 삭제할 수 있다.

//삭제
print(dic)	//기존 배열 출력
dic.removeValue(forKey: "green")    //green 키-값 삭제
print(dic)	//삭제된 배열 출력


출력

딕셔너리또한 반복문과 사용하면 편리하게 출력 및 제어할 수 있다.

//개별 출력
for i in dic {
    print(i)    //튜플형태로 출력된다.
    print(i.key, i.value)	//키와 값을 따로 출력할 수 있다.
}
print("------------\n")

for (k, v) in dic{
    print(k,v)	//키와 값을 더 간략하게 출력할 수 있는 방법이다.
}

var k = dic.keys    //키만 따로 뽑아낼 수 있다.
print(k)    //배열형태로 출력된다.

var v = dic.values //값만 따로 뽑아낼 수 있다.
print(v)    //배열형태로 출력된다.


메소드

딕셔너리의 여러가지 메소드를 통해 데이터를 반환받을 수 있다.

//비어있는 딕셔너리인지 확인
print(dic.isEmpty)

//딕셔너리의 갯수 출력
print(dic.count)

//딕셔너리 비우기
dic.removeAll()
print(dic.isEmpty)
print(dic.count)


Dictionary 예제

중복된 숫자의 배열을 받아서 각 숫자가 몇번 중복되었는지 딕셔너리형태로 출력해보자.

let hit = [3,4,7,8,1,3,5,7,1,3,4,8,1,1] //안타 친 등번호 순서
var hitData = [Int:Int]()   //비어있는 딕셔너리 생성

for i in hit{
    var no = 1
//    print(i, hitData[i]==nil)   //해당 데이터가 중복인지 확인.
    
    if hitData[i] != nil{   //중복된 자료라면,
        no += hitData[i]!   //hitData[i]의 값을 1증가한다.
    }
    
    hitData[i] = no  //중복이 되지 않으면서 대입이 된다.
}
print(hit)	//기존 데이터 출력
print(hitData)  //[등번호 : 안타횟수] 형태로 출력

[번호 : 중복횟수] 형태로 출력이 되지만, 딕셔너리는 순서없는 자료형이기에, 랜덤하게 출력이 된다. 오름차순으로 정렬하려면 따로 가공하여 출력해야한다.

//dictionary는 순서없는 자료형이기에, sort()함수는 불가능. sorted()함수를 이용하여 정렬된 자료를 반환받아 처리해야한다.
for k in hitData.keys.sorted(){
    print("\(k):\(hitData[k]!)개","",separator: "\t",terminator: "")   //등번호, 안타횟수 출력
}

최종출력은 다음과 같다. print()함수의 separactor 속성은 다음 데이터 출력 시 기존 데이터와 구분하기 위해 출력내용을 정해주는 속성이다. 한번에 데이터가 두개 이상 출력이 되어야 적용되므로 기존 자료와 공백 데이터("")를 출력하게 작성했다.


Set

딕셔너리는 키와 값으로 이루어진 순서없는 데이터의 모음(컬렉션 타입)이다. 하지만 키-값 쌍의 형태가 아닌 단일형태의 순서없는 데이터 모음이 필요한 경우 Set을 사용한다. 즉 키로만 이루어진 딕셔너리라고 생각하면 된다.

var 변수이름 : Set<자료형> = [자료,자료,자료]

var arr = [11,22,11,33,22,44,11,55]     //배열    중복데이터가 허용된다. 순서가 있다.
var ss1:Set<Int> = [11,22,11,33,22,44,11,55]    //set 중복데이터는 생략되어 저장된다. 순서가 없다.

print(arr)
print(ss1)

값으로 이루어진 딕셔너리가 아닌 키로만 이루어진 모임이라고 설명한 것은 바로 데이터의 중복이 허용되지 않는다는 점 때문이다. 일반적인 배열과 큰 차이이다. 출력 모습도 배열은 인덱스 순서로 출력되는 반면, set은 순서없이 출력이 되는 모습을 볼 수 있다.


선언 및 초기화

var ss2 = Set<String>()     //빈 set생성
var ss3:Set<Int> = []       //빈 set생성

print(ss2)
print(ss3)

ss2 = ["a","b","d"]     //빈 set 초기화
ss3 = [3,4,4,5,6,7]     //빈 set 초기화

print(ss2)
print(ss3)


요소 갯수 출력

var ss1:Set<Int> = [11,22,11,33,22,44,11,55]

//set 요소 갯수출력
print(ss1.count)

중복이 허용되지 않아 ss1의 요소는 5개로 출력한다.


반복문 출력

var ss1:Set<Int> = [11,22,11,33,22,44,11,55]

//반복문 출력
for i in ss1 {
    print(i)    //원소를 하나씩 가지고 올 수 없다. 순서가 없기 때문이다.
}

Set은 배열과 달리 인덱스가 없기에 반복문을 통해 요소를 하나씩 출력할 수 없다. 


요소 검색, 추가, 삭제

var ss1:Set<Int> = [11,22,11,33,22,44,11,55]

//요소 검색
print(ss1.contains(33))	//요소 33이 있는가?
print(ss1.contains(100))//요소 100이 있는가?

//요소 추가
ss1.insert(77)  //요소 77 추가 *중복데이터를 추가하면 변화가 일어나지 않는다.
print(ss1)

//요소 삭제
ss1.remove(22)  //요소 22 삭제
print(ss1)


isEmpty, 전체삭제

var ss1:Set<Int> = [11,22,11,33,22,44,11,55]

//빈 set인지 확인
print(ss1.isEmpty)  //bool return

//요소 전체삭제
ss1.removeAll() //요소 전체삭제
print(ss1.isEmpty)

isEmpty메소드를 통해 비어있는 배열인지 확인 후 bool값을 반환해준다.


set 집합연산

set에는 여러가지 집합연산이 메소드 형태로 존재한다.

var s1 : Set<Int> = [1,2,3,4,5,6]   //순서없는 자료 묶음
var s2 : Set<Int> = [4,5,6,7,8,9]

print("s1 \(s1)")
print("s2 \(s2)")

var rr = s1.union(s2)   //합집합
print("s1.union(s2) \(rr)")

rr = s1.intersection(s2)    //교집합
print("s1.intersection(s2) \(rr)")

rr = s1.symmetricDifference(s2) //합집합 - 교집합
print("s1.symmetricDifference(s2) \(rr)")

rr = s1.subtracting(s2) //s1 차집합 s2
print("s1.subtracting(s2) \(rr)")

rr = s2.subtracting(s1) //s2 차집합 s1
print("s2.subtracting(s1) \(rr)")


set 예제1

set을 사용하여 로또 번호 생성기를 작성해보자.

var lotto1 = [Int]()
var lotto2 = Set<Int>()

while true {
    let no = Int.random(in: 1...45)	//1부터 45까지 랜덤번호 생성 메소드
    
    lotto1.append(no)   //배열에 요소 추가
    lotto2.insert(no)   //set에 요소 추가
    
    if lotto2.count == 7 {  //set의 요소가 7개가 되면 종료
        break
    }
}

print("lotto1: \(lotto1)")  //배열의 경우 겹치는 수가 존재한다.
print("lotto2: \(lotto2)")  //set의 경우 겹치는 수가 없다.

배열과의 비교를 통해 두개를 작성했다. 배열의 경우 중복이 허용되기 때문에 중복된 숫자가 생성된다. 하지만 set의 경우 중복을 허용하지 않기에 요소가 7개가 될 때 반복문을 탈출하면 된다.


set 예제2

set을 이용하여 빙고판을 만들어 보자.

var number = Set<Int>()
var cnt = 0

while number.count < 25{    //set의 요소가 25가 될때까지 랜덤숫자 삽입
    number.insert(Int.random(in: 1...100))
}

for i in number{
    cnt += 1
    print(i,terminator: "\t")   //줄 변경 없이 출력
    if cnt % 5 == 0 {   //cnt가 5의 배수가 되면 줄 변경
        print()
    }
}

set의 중복 불허용의 특성을 이용하여 5x5 숫자빙고를 출력하였다. 


set 예제3

각 리스트의 중복을 제거하는 예제이다. 

let first:Set<String> = ["박재상","박정권", "최정", "김광현", "엄정욱", "박희수", "이호준"]
let second:Set<String> = ["이호준", "엄정욱", "박재홍", "이신협", "장동건"]
let fa:Set<String> = ["이병규", "이승엽", "박정권", "장동건", "박용택", "홍성흔"]

print("변경 전---------------------------")
print("1군 리스트:",first)
print("2군 리스트:",second)
print("FA 리스트:",fa)

let afterFirst = first.subtracting(second).subtracting(fa)  //1군 - 2군 - FA
let afterSecond = second.subtracting(fa)	//2군 - FA
let afterFa = fa.subtracting(first).subtracting(second) //FA - 1군 - 2군

print("변경 후---------------------------")
print("1군 리스트:",afterFirst)
print("2군 리스트:",afterSecond)
print("FA가능 리스트:",afterFa)

야구를 안봐서 뭐하는 예제인지는 모르겠다. 

'iOS > TJ' 카테고리의 다른 글

day11_param, return, funcCall  (0) 2021.06.18
day10_func()  (0) 2021.06.17
day08_multiArray, tuple  (0) 2021.06.03
day07_array  (0) 2021.06.02
day06_control flow_loop  (0) 2021.05.27

+ Recent posts