【问题标题】:reduce function is printing an empty dictionary [:]reduce 函数正在打印一个空字典 [:]
【发布时间】:2019-06-17 13:09:48
【问题描述】:

我已在此question 中成功地将我的字典键减少为没有真正 json 模型的伪代码。我在上一个问题中实现的目标是只返回具有匹配值的键。所以输出是一个类似于["WoW": ["@jade", "@kalel"] 的字典。正是我需要的。当然可能还有其他比赛,我也想退回这些比赛。

现在我有了一个合适的 json 模型,reduce 函数打印出一个空字典 [:]。是.reduce(into: [String:[String]]() 中的类型导致了问题吗?

所有数据都在打印,因此 json 和模型结构必须正确。

json

[
{
    "id": "tokenID-tqkif48",
    "name": "@jade",
    "game": "WoW",
    "age": "18"
},
{
    "id": "tokenID-fvkif21",
    "name": "@kalel",
    "game": "WoW",
    "age": "20"
}
]

用户模型

public typealias Users = [UserModel]
public struct UserModel: Codable {

public let name: String
public let game: String
// etc...

enum CodingKeys: String, CodingKey {
    case name
    case game
    // etc...

游乐场

guard let url = Bundle.main.url(forResource: "Users", withExtension: "json") else {
    fatalError()
}
guard let data = try? Data(contentsOf: url) else {
    fatalError()
}

let decoder = JSONDecoder()

do {
    let response = try decoder.decode([UserModel].self, from: data)
    for userModel in response {

        let userDict: [String:String] = [ userModel.name:userModel.game ]

        let reduction = Dictionary(grouping: userDict.keys) { userDict[$0] ?? "" }.reduce(into: [String:[String]](), { (result, element) in
            if element.value.count > 1 {
                result[element.key] = element.value
            }
        })
        // error catch etc
}

【问题讨论】:

  • @tymac 我可以编译而无需花时间按摩 json。
  • 感谢您的意见。这就是我拥有的所有代码。没有什么需要按摩的。 Vadian 和 OOper 都在几分钟内回答,无需额外代码。模型和一切都清晰可见。
  • 换一种说法。我想要一些可以复制到空 Swift 文件中的内容,单击编译,然后查看您的问题。现在你的代码做了很多与你的问题无关的事情。它从 main bundel 加载一个 Users.json 文件(这意味着潜在的回答者需要创建一个新的 xcode 项目,并创建这样一个文件),它解码 JSON(即使可以使用直接初始化的 @987654330 重新创建同样的问题@structs,无需解析JSON)等
  • 参见stackoverflow.com/help/mcve 特别是:“尽可能少地使用仍然产生相同问题的代码”、“创建一个新程序,只添加查看问题所需的内容”、“消除任何与问题无关的问题”等。

标签: json swift dictionary reduce codable


【解决方案1】:

您的代码太复杂了。您可以通过 game 对数组进行分组,只需使用

let response = try decoder.decode([UserModel].self, from: data)
let reduction = Dictionary(grouping: response, by: {$0.game}).mapValues{ usermodel in usermodel.map{ $0.name}}

【讨论】:

  • 请查看我添加到问题底部的新代码。如果这是正确的,我仍然会收到 Type of expression is ambiguous without more context 错误。
  • 删除循环。
  • 我更新了答案以将值映射到它们的名称。使用给定的 JSON,一定不会发生错误。
【解决方案2】:

更新我可能弄错了你想得到什么。下面还有一个代码,请检查结果并选择一个你想要的。

如果你想使用reduce(into:updateAccumulatingResult:),你可以这样写。

do {
    let response = try decoder.decode([UserModel].self, from: data)
    let userArray: [(name: String, game: String)] = response.map {($0.name, $0.game)}

    let reduction = userArray.reduce(into: [String:[String]]()) {result, element in
        if !element.game.isEmpty {
            result[element.name, default: []].append(element.game)
        }
    }
    print(reduction)
} catch {
    print(error)
}

如果您更喜欢 Dictionary 的初始化程序,这可能会起作用:

do {
    let response = try decoder.decode([UserModel].self, from: data)
    let userArray: [(name: String, games: [String])] = response.map {
        ($0.name, $0.game.isEmpty ? [] : [$0.game])
    }

    let reduction = Dictionary(userArray) {old, new in old + new}
    print(reduction)
} catch {
    print(error)
}

两个输出:

["@jade": ["WoW"], "@kalel": ["WoW"]]

无论如何,您将循环、Dictionary(grouping:)reduce(into:) 以及 userDict.keys 组合在一起的方式使事情变得过于复杂。


ADDITION当你想得到一个带有键的字典作为游戏时:

do {
    let response = try decoder.decode([UserModel].self, from: data)
    let userArray: [(game: String, name: String)] = response.compactMap {
        $0.game.isEmpty ? nil : ($0.game, $0.name)
    }

    let reduction = userArray.reduce(into: [String:[String]]()) {result, element in
        result[element.game, default: []].append(element.name)
    }
    print(reduction)
} catch {
    print(error)
}

或者:

do {
    let response = try decoder.decode([UserModel].self, from: data)
    let userArray: [(game: String, names: [String])] = response.compactMap {
        $0.game.isEmpty ? nil : ($0.game, [$0.name])
    }

    let reduction = Dictionary(userArray) {old, new in old + new}
    print(reduction)
} catch {
    print(error)
}

输出:

["WoW": ["@jade", "@kalel"]]

【讨论】:

  • 谢谢。我会赞成你的回答。我将@vadian 的答案标记为正确,因为他首先使用了正确的算法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多