将`[URLQueryItem]`转换为`[String: Any]`

3

目前我有这个臃肿的reduce函数...

blah: [String: Any] = queryItems.reduce([String: Any]()) {
    (params: [String: Any], queryItem: URLQueryItem) in

    var output = params

    output[queryItem.name] = queryItem.value

    return output
}

我相信有更简单的方法来做这件事,但我无法理解那将如何工作。

是否有“更好”的方法来完成这个任务?

所谓“更好”,指的是更干净、更短、更优雅等等……


4
小提示:某些API中可能会有多个具有相同键的参数,参数的顺序对一些API很重要。因此,在将查询参数表示为字典时,请注意这一点。 - Sulthan
@Sulthan 谢谢你的警告。对于我们特定的用例来说,这不是问题,但我会注意未来的情况。另外...我很快就会更新我的代码,所以最终可能不需要这个了。 - Fogmeister
2个回答

6

可以使用reduce(into:_:)代替reduce(_:_)。这样既可以节省代码行数,又不必为每次迭代复制params的开销:

let blah: [String: Any] = (urlComponents.queryItems ?? []).reduce(into: [:]) {
    params, queryItem in 
    params[queryItem.name] = queryItem.value
}

当结果是一个写时复制类型(例如数组或字典)时,此方法比reduce(_:_:)更为高效。


2
reduce(into:) 是 Swift 最近的一个伟大但鲜为人知的宝石。这使得非标量 reduce 可用。 - Rob Napier
3
Swift 是一种类型推断语言。顺便说一下,在这里你可以简单使用可选链式调用 let blah = urlComponents.queryItems?.reduce(into: [:]) { $0[$1.name] = $1.value } ?? [:],如果值始终为字符串,则无需使用 Any 作为值类型。 - Leo Dabus

2
你可以通过以下方式,将查询项的名称和值创建为字典:
```python dict((x.split('=') for x in query.split('&'))) ```
其中,`query`是查询字符串。
let items = urlComponents.queryItems ?? []
let dict = Dictionary(items.lazy.map { ($0.name, $0.value as Any) },
                      uniquingKeysWith: { $1 })

在名称重复的情况下,后面的值会覆盖先前的值(可以使用uniquingKeysWith:参数进行控制)。
或者去掉as Any强制转换,以获取类型为[String: String?]的字典:
let items = urlComponents.queryItems ?? []
let dict = Dictionary(items.lazy.map { ($0.name, $0.value ) },
                      uniquingKeysWith: { $1 })

最初的回答
或者
let items = urlComponents.queryItems ?? []
let dict = Dictionary(items.lazy.map { ($0.name, [$0.value] ) },
                      uniquingKeysWith: +)

构建一个类型为[String : [String?]]的字典,保存每个名称的所有值。最初的回答。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接