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.

1

2 Answers 2

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
Sign up to request clarification or add additional context in comments.

4 Comments

Edited to use conditional binding rather than is + as!
Should I also edit to use map over repeated appends?
@Alexander Go ahead :-)
@Alexander Thank you very much.
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

1 Comment

thanks for that. The order is irrelevant, maybe a more swifty approach, something with map or flatmap?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.