缩小功能正在打印一个空字典[:]

时间:2019-01-23 21:18:59

标签: json swift dictionary reduce codable

在此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"
}
]

UserModel

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
}

2 个答案:

答案 0 :(得分:2)

您的代码太复杂。您只需使用{p>即可通过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}}

答案 1 :(得分:1)

更新,我可能会误解您想要获得的东西。下面还有另一个代码,请检查结果并选择所需的代码。

如果您想使用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.keysdo { 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"]]

输出:

#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

void pocket(void);
int pocket_add(int op1, int op2);

#ifdef __cplusplus
}
#endif