0

I have a struct and I want to convert that into Dictionary with properties as Key and their value as Value but the key should not be the property name but something different i.e. shopping_list_id OR shopping_list_name.

struct AddItemToEvent {
  var key: String
  var shoppingListId: String   //shopping_list_id
  var shoppingListName: String   //shopping_list_name
  var commonName: String
  var storeCode: String
  var sourceType: String
  var sourceId: String
  var isDefaultList: String
  var storeLocation: String

//  shopping_list_id, shopping_list_name, common_name, store_code, source_type (offer, promotion, normal, favourite), source_id, default_list, store_location, client_id 
}

I need to have a method for struct getDictionaryEquivalent() which can result something like ["shopping_list_name":"", "shopping_list_id": "", ......]

nikksindia
  • 1,147
  • 1
  • 10
  • 18
  • https://stackoverflow.com/questions/46597624/can-swift-convert-a-class-struct-data-into-dictionary – Dilan Apr 29 '20 at 10:00
  • @DilanAnuruddha: This doesn't fulfil my requirement as the dictionary key shouldn't be same as property name. – nikksindia Apr 29 '20 at 10:03
  • What is the problem with writing such a function, seems pretty straightforward to me? – Joakim Danielson Apr 29 '20 at 10:09
  • @JoakimDanielson: The problem is dictionary key shouldn't be same as property name. Like we do in Codable using CodingKeys – nikksindia Apr 29 '20 at 10:10
  • @JoakimDanielson: I want to have a generic solution (if available) – nikksindia Apr 29 '20 at 10:13
  • "The problem is dictionary key shouldn't be same as property name. Like we do in Codable using CodingKeys" You know you can use custom keys and not names your properties the same as the keys inside the JSON, right? Is the goal writing a Dictionary or a JSON? – Larme Apr 29 '20 at 10:41
  • @Larme Either of them – nikksindia Apr 29 '20 at 12:21

1 Answers1

1

You can use a regular expression to convert to snake case and use reflection (Mirror) to convert to a dictionary.

The regex is rather simple and will not work so well if you for instance have several uppercase letters after each other so this part could be improved if needed.

func snakeKeyDictionary(_ mirror: Mirror) -> [String: Any] {
    var dictionary = [String: Any]()
    for (key, value) in mirror.children {
        if let key = key {
            let snakeKey = key.replacingOccurrences(of: #"[A-Z]"#, with: "_$0", options: .regularExpression).lowercased()
            dictionary[snakeKey] = value
        }
    }
    return dictionary
}

Example if usage

let item = AddItemToEvent(key: "1", shoppingListId: "12", shoppingListName: "List", 
    commonName: "some", storeCode: "ABC", sourceType: "A", sourceId: "fgd", 
    isDefaultList: "yes", storeLocation: "home")

let mirror = Mirror(reflecting: item)
print(snakeKeyDictionary(mirror))

prints

["common_name": "some", "is_default_list": "yes", "store_code": "ABC", "store_location": "home", "key": "1", "shopping_list_name": "List", "source_id": "fgd", "shopping_list_id": "12", "source_type": "A"]

But of course if the goal is to create json data it is quite simple

Make the struct conform to Codable and then set the keyEncodingStrategy property when encoding

let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52