0

I got an dictionary which looks like:

["foo": "whatever", "this": "that", "category": ["cat1", "cat2"]]

and I need it to be a string like:

foo=whatever&this=that&category=cat1&category=cat2

so that if a key has values of type array, the key should occur multiple times in the string.

Leo
  • 380
  • 1
  • 17
  • You should check out `NSURLComponents` and `NSQueryItem`. It does exactly what you want: https://stackoverflow.com/a/39770846/3141234 – Alexander Jul 12 '17 at 16:46

2 Answers2

2

As Alexander suggested this is a solution with URLComponents and URLQueryItem

import Foundation

let dict: [String: Any] = [
    "foo": "whatever",
    "this": "that",
    "category": [
        "cat1",
        "cat2"
    ]
]

var queryItems = [URLQueryItem]()
for (key, value) in dict {
    if let strings = value as? [String] {
        queryItems.append(contentsOf: strings.map{ URLQueryItem(name: key, value: $0) })
    } else {
        queryItems.append(URLQueryItem(name: key, value: value as? String))
    }
}

var urlComponents = URLComponents(string: "http://myserver.com")!
urlComponents.queryItems = queryItems
let url = urlComponents.url!
print(url.absoluteString) // => http://myserver.com?this=that&foo=whatever&category=cat1&category=cat2

A similar solution, but simpler, using flatMap:

let queryItems = dict.flatMap { key, value -> [URLQueryItem] in
    if let strings = value as? [String] {
        return strings.map{ URLQueryItem(name: key, value: $0) }
    } else {
        return [URLQueryItem(name: key, value: value as? String)]
    }
}

var urlComponents = URLComponents(string: "http://myserver.com")!
urlComponents.queryItems = queryItems
let url = urlComponents.url!
print(url.absoluteString) // => http://myserver.com?this=that&foo=whatever&category=cat1&category=cat2
Alexander
  • 59,041
  • 12
  • 98
  • 151
vadian
  • 274,689
  • 30
  • 353
  • 361
0

I believe something like this should work if you know your dictionary types:

var string = ""
for key in dict.keys {
    if let array = dict[key] as? [String] {
        for arrayItem in array {
            string += "\(key)=\(arrayItem)&"
        }
    }
    else if let value = dict[key] as? String {
        string += "\(key)=\(value)&"
    }
}

print(string.substring(to: string.index(before: string.endIndex)))

Noting that this might print them in a random order because the dictionary is not ordered

Prientus
  • 733
  • 6
  • 15
  • thanks for that. The order is irrelevant, maybe a more swifty approach, something with map or flatmap? – Leo Jul 12 '17 at 16:42