iOS 공부하는 감자

Day3) 배열, 딕셔너리, 세트, 열거형 + 알고리즘 본문

22 베이직 챌린지

Day3) 배열, 딕셔너리, 세트, 열거형 + 알고리즘

DongTaTo 2022. 1. 5. 22:30
반응형

배열(Array)

배열의 특징

  • 동일한 자료형만 저장 가능
  • 배열 내부의 값은 순서가 있음 (index / zero based)
  • 순서가 있는 값들을 저장할 때 유용

 

배열 선언방식

let someArray: [Int]
let someArray2: Array<Int>

 

 

 

배열에 사용 가능한 메서드

1. 저장된 요소의 갯수 확인 : count

 

 

2. 배열이 비었는지 확인 : isEmpty

 

 

3. 배열 요소에 접근

let someArray: [Int] = [1, 2, 3]

// 1. [index]로 접근
someArray[1]      // 2

// 2. [index범위]로 접근
someArray[0...1]  // [1, 2]

// 3. first / last로 접근
someArray.first   // Optional(1)
someArray.last    // Optional(3)

 

  • index로 접근하는 경우 해당 index에 값이 없으면 오류를 발생하므로 주의해야됨 (index out of range....)
  • first, last를 사용하여 접근하는 경우에는 반환 타입이 Optional이라서 값이 없어도 오류를 발생하지 않고 nil을 반환함

 

4. 배열에 요소 추가

// 1. append: 배열의 마지막에 추가
var someArray: [Int] = [1, 2, 3]
someArray.append(4)                      // [1, 2, 3, 4]
someArray.append(contentsOf: [1, 2, 3])  // [1, 2, 3, 4, 1, 2, 3]

// 2. insert: 배열 중간에 추가
var someArray2: [Int] = [1, 2, 3]
someArray2.insert(0, at: 0)                      // [0, 1, 2, 3]
someArray2.insert(contentsOf: [99, 999], at: 1)  // [0, 99, 999, 1, 2, 3]

contentsOf를 사용하면 배열을 추가할 수 있음

배열은 내부 요소들이 순서대로 저장되어 있기 때문에 insert를 사용해서 중간에 값을 추가하면 배열을 재배치하기 때문에 오버헤드가 발생

가능하면 오버헤드 발생이 없는 append 메서드를 사용하는게 좋음

 

 

5. 배열 요소 변경

// index를 입력해서 변경
var someArray: [Int] = [1, 2, 3]
someArray[0] = 100                  // [100, 2, 3]
someArray[1...2] = [20, 30]         // [100, 20, 30]

// replaceSubRange를 사용해서 변경 (범위)
var someArray2: [Int] = [1, 2, 3]
someArray2.replaceSubrange(1...2, with: [200, 300])   // [1, 200, 300]

 

 

 

6. 배열 요소 삭제

var someArray: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9]

someArray.remove(at: 1)    // [1, 3, 4, 5, 6, 7, 8, 9]
someArray.removeFirst()    // [3, 4, 5, 6, 7, 8, 9]
someArray.removeFirst(2)   // [5, 6, 7, 8, 9]
someArray.removeLast()     // [5, 6, 7, 8]
someArray.removeLast(2)    // [5, 6]
someArray.removeAll()      // []

 

 

7. 배열 요소 검색

  • contains(_: )  = 배열에 전달하는 요소가 있는지 확인
  • contains(where: )  = 클로저 조건에 맞는 값이 있는지 확인
  • first(where: )  = 클로저 조건에 맞는 가장 첫 번째 요소의 값을 리턴
  • firstIndex(where: )  = 클로저 조건에 맞는 가장 첫 번째 요소의 index를 리턴
  • last(where: )  = 클로저 조건에 맞는 가장 마지막 요소의 값을 리턴
  • lastIndex(where: )  = 클로저 조건에 맞는 가장 마지막 요소의 index를 리턴

 

8. 배열의 정렬

  • sort()  = 해당 배열을 정렬
  • sorted()  = 정렬된 배열을 새로 생성

 

9. 배열 요소 바꾸기

var someArray: [Int] = [1, 2, 3]
someArray.swapAt(0, 2)  // [3, 2, 1]

 

 

10. 무작위로 섞기 : shuffle()

 

 

 

딕셔너리(Dictionary)

딕셔너리 특징

  • Key: Value 쌍으로 이루어지는 자료구조
  • Key 값을 사용하여 Value에 접근
  • 정렬되지 않음
  • Key는 중복될 수 없음 (Value는 중복 가능)
  • Array와 마찬가지로 모든 Key, Value는 각각 같은 자료형으로 이루어짐
  • 해시 테이블 형식으로 동작한다.

 

딕셔너리 선언방식

var someDictionary: [Int: String] = [1: "one", 2: "two"]

var someDictionary2: [Int: String] = [Int: String]()

 

딕서너리에서 사용 가능한 메서드

1. 요소에 접근하기

var someDictionary: [Int: String] = [1: "one", 2: "two"]
someDictionary[1]   // Optional("one")

 

해당 Key에 해당하는 Value가 없을 수 있으니 반환 값이 Optional로 나옴

 

Optional로 나오지 않게 하려면 요소에 접근할 때 default 값을 지정해주거나

?? 연산자를 사용하여 nil일 경우 반환할 값을 지정해줘도 됨 (대신 이 방법은 값을 조회할 때만 사용 가능)

let someDictionary: [String: Int] = ["dong": 25, "jun": 27, "kang": 24]

print(someDictionary["dong"])             // Optional(25)
print(someDictionary["dong"] ?? 0)        // 25
print(someDictionary["dong", default: 0]) // 25

print(someDictionary["min"])              // nil
print(someDictionary["min"] ?? 0)         // 0
print(someDictionary["min", default: 0])  // 0

 

 

2. 요소 추가

var someDictionary: [Int: String] = [1: "one", 2: "two"]

// 요소 추가
someDictionary[3] = "three"

someDictionary.updateValue("four", forKey: 4)

 

 

3. 요소 업데이트

var someDictionary: [String: Int] = ["dong": 25, "jun": 27, "kang": 24]

// dictionary 값 업데이트

// 기존에 있던 key를 통해 접근하면 값을 업데이트
someDictionary.updateValue(250, forKey: "dong")
print(someDictionary["dong"]!)            // 250

// 기존에 없던 key를 통해 접근하면 key: value 새로 생성
someDictionary.updateValue(270, forKey: "yong")
print(someDictionary["yong"]!)            // 270


// 기존에 있던 값에 +=100 연산 수행
someDictionary["kang", default: 0] += 100
print(someDictionary["kang"]!)            // 124

// 기존에 없던 값에 +=100 연산 수행 (default를 사용하여 해당 키 값이 없으면 value를 0으로 설정한 값을 추가한 후 += 연산 진행)
someDictionary["jin", default: 0] += 100
print(someDictionary["jin"]!)              // 100

 

 

 

4. 요소 삭제

  • Key로 접근해서 Value에 nil 넣기
  • .removeValue(forKey: )
  • .removeAll()

 

5. 점연산자 사용해서 Key, Value를 나열

  • .Keys  = Key만 나열
  • .Value  = Value만 나열
  • 순서가 없는 Collection type이라서 매번 뒤죽박죽으로 나옴 -> .sorted() 사용으로 정렬해서 나열 가능

 

6. 요소 검색

  • .contain(where: )
  • .first(where: )
  • filter(_: )
  • 딕셔너리는 클로저를 이용해서 요소를 검색

 

6. isEmpty, count 등 Array에서 사용하던 메서드도 사용 가능..

 

 

세트(Set)

세트 특징

  • 순서가 없는 자료구조
  • 내부 Value들이 유일한 값을 가짐
  • 중복이 없는 유니크한 값들을 관리할 때 유용
  • 동일한 자료형으로 구성
  • 해시를 통해 값을 저장해서 Array보다 검색 속도가 빠름 (..?)

 

세트 선언방식

var someSet: Set<Int> = [1, 2, 3, 4, 5, 1]  // [5, 2, 1, 3, 4]

중복되는 값은 알아서 없어짐

 

 

세트에서 사용 가능한 메서드

1. 요소 갯수 확인 : count

 

2. 요소 있는지 확인 : contain

 

3. 요소 삭제 : remove, removeAll

 

4. 요소 추가 : insert

 

 

 

 


 

 

 

열거형(enum)

연관된 항목들을 묶어서 표현할 수 있는 타입

 

 

열거형 선언방식

enum School {
    case primary
    case elementary
    case middle
    case high
}

 

 

사용하는 상황

  • 제한된 선택지를 주고 싶을 때
  • 정해진 값 외에는 입력받고 싶지 않을 때
  • 예상된 입력 값이 한정되어 있을 때

 

원시값 (Raw Value)

열거형의 각 항목(case)는 그 자체로도 하나의 값이지만 항목의 원시값도 가질 수 있음

  • 특정 타입으로 지정된 값을 따로 가질 수 있다는 의미
  • 원시값을 가지려면 열거형을 정의할 때 이름 옆에 원시값의 데이터 타입을 명시해주면 됨
  • enum School: String {
        case primary = "유치원"
        case elementary = "초등학교"
        case middle = "중학교"
        case high = "고등학교"
    }
  • 원시값을 사용하려면 열거형 항목에서 .rawValue 를 사용해서 가져올 수 있음

 

연관값

  • 열거형의 항목들은 관련된 연관값을 가질 수 있음
  • 연관값은 각 항목 옆에 소괄호로 묶어서 표현
  • 연관값의 타입을 열거형으로 지정해서 한정된 값을 받을 수도 있음
  • enum School {
        case primary
        case elementary(schoolName: String)
        case middle
        case high(numberOfStudent: Int)
    }
    
    let swiftSchool: School = .elementary(schoolName: "swift")
    
    let iPhoneSchool: School = .high(numberOfStudent: 10)

 

 

 

 


알고리즘

 

최소, 최대를 구하는 코드를 작성하는데 계속 시간 초과가 나왔다...;;

나름 간결하다고 생각했는데.. 문자열을 공백 기준으로 분리하는 과정에서 사용한 components가 split보다 시간이 조금 더 걸려서 시간 초과가 뜬거였다 .. ㅎㅎ

 

시간초과 코드

let numberOfValue: Int = Int(readLine()!)!
let inputValue: [Int] = readLine()!.components(separatedBy: " ").map({Int($0)!})
print("\(inputValue.min()!) \(inputValue.max()!)")

 

성공 코드 (components -> split)

let numberOfValue: Int = Int(readLine()!)!
let inputValue: [Int] = readLine()!.split(separator: " ").map({Int($0)!})
print("\(inputValue.min()!) \(inputValue.max()!)")

 

 

 

 


 

 

GitHub - DongHee-Sin/SocobanTest: 소코반 게임 구현하기

소코반 게임 구현하기. Contribute to DongHee-Sin/SocobanTest development by creating an account on GitHub.

github.com

 

 

 

 

 

 

 

 

 

 

 

반응형