ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Dictionary.init(uniqueKeysWithValues:)
    Swift 2021. 8. 31. 19:30

    안녕하세요. 그린입니다🟢

    이번 포스팅에서는 Dictionary.init(uniqueKeysWithValues:)에 대해 학습해보겠습니다💁🏻

     

    딕셔너리가 뭐에요??

    우선 딕셔너리는 key와 value로 이루어진 데이터를 담는 컨테이너입니다.

    특징이라하면 각 value는 고유의 유일한 key와 연결되어 있습니다.

    딕셔너리는 array처럼 순서가 있지 않기에 각 물려있는 key값으로 value값을 찾을 수 있습니다.

     

    즉 딕셔너리를 표현한다면 Dictionary<KeyType, ValueType>로 표현할 수 있습니다📑
    그렇다면 딕셔너리의 키값은 고유의 값이니 Hashable 해야겠쬬!?

    그런데 우리가 쓰는 딕셔너리의 키값은 대부분 swift에서 기본 제공하는 Int, String, enum 등등일겁니다!

    해당 기본제공되는 자료형 타입들은 이미 Hashable해서 따로 지정하지 않고 쓰는거에요😀

     

    딕셔너리를 간략히 소개한다 했는데 서두가 너무 길었어요!
    그럼 본격적으로 오늘 학습하려한 딕셔너리를 초기화하는 방법에 대해 알아보겠습니다..!
    다양한 방법이 있지만 저는 Dictionary.init(uniqueKeysWithValues:)에 대해 알아보려해요.

     

    왜 Dictionary.init(uniqueKeysWithValues:)를 알려하죠?

    어떠한 커스텀한 자료형이 있다고 가정합니다.

    예를들어 아래와 같이 생각해볼 수 있겠어요!

    let sampleData: [Sample] = [...]
    
    struct Sample: {
      var title: String
      var subtitle: String
      var checked: Bool
      ...
    }

    이러한 커스텀한 타입의 데이터를 만약 서버의 API와 통신하려합니다.

    서버의 API 필드값들은 정해진 Timestamp, Bool, Num, String, Map 등등.. 밖에 인식하지 못합니다.

    즉 저대로 그냥 넘겨주면 안되겠죠?

    지정된 API 필드 형태에 맞게 넘겨주어야합니다.

     

    그러면 예를들어 가정해보겠습니다.

    서버의 API 필드값이 map으로 [String:Bool]의 데이터들이 쫙~~ 있습니다.

    이 데이터에 위의 sampleData에서 title과 checked의 정보만 가져와 서버로 넘겨주고 싶다면..?

     

    먼저 저는 Dictionary.init(uniqueKeysWithValues:)를 사용하지 못하였을때는 아래와 같이 했습니다.

    let convertedData = sampleData.map({ data -> [String:Bool] in
      guard let title = data.title else { return [:] }
      guard let checked = data.checked else { return [:] }
      return [title:checked]
    })
    .flatMap({ $0 })
    .reduce([String:Bool]()){ (dict, tuple) in
      var updatedDict = dict
      updatedDict.updateValue(tuple.1, forKey: tuple.0)
      return updatedDict
    }

    이런식으로요😅

    map을 거치게 되면 [[String:Bool]]로 어레이 맵 타입이 됩니다.

    이걸 flatMap을 거치고 reduce를 거쳐 [String:Bool]으로 타입을 맞춰줍니다.

    이렇게해도 물론 잘 동작하고 됩니다!!

     

    그러나, 위와 같이하면 코드가 좀 복잡해지죠..?

    이럴때 더 간단히 아예 생성할때 딕셔너리로 초기화 시켜버리는 겁니다.

    let convertedData = sampleData.map({ data -> (String,Bool) in
      guard let title = data.title else { return ["",false] }
      guard let checked = data.checked else { return ["",false] }
      return (title:checked)
    })

    어때요 훨~씬 간략해졌죠?

    저기서 String,Bool이 key와 value입니다. key/value 타이핑이 생략되었을뿐!

    이렇게 한다라고 한다라면 map을 해줘도 [[String:Bool]]이 되지 않고 딕셔너리로 초기화 할 수 있습니다.

     

    자.. 멀리 돌고 돌았지만 저는 현재 저럴때 간략하게 나타내고 싶어서 학습을 해보았어요!

    당연히 더 다양하게 사용되겠죠😳

    그런건 다음번에🤯

     

    [참고자료]

    https://developer.apple.com/documentation/swift/dictionary/3127165-init

     

    Apple Developer Documentation

     

    developer.apple.com

    'Swift' 카테고리의 다른 글

    Swift - Markdown  (2) 2021.10.20
    KeyPath  (0) 2021.09.04
    순수함수와 사이드이펙트  (0) 2021.08.22
    Safe Array  (0) 2021.07.24
    ReactorKit으로 계산기 구현하기  (0) 2021.07.05
Designed by Tistory.