Функция Reduce печатает пустой словарь [:] - PullRequest
0 голосов
/ 24 января 2019

Я успешно сократил свои словарные ключи в этом вопросе как псевдокод без реальной модели json. Цель, которую я выполнил в предыдущем вопросе, - вернуть только те ключи, которые имеют совпадающие значения . Таким образом, на выходе получается словарь, который выглядит примерно так: ["WoW": ["@jade", "@kalel"]. Именно то, что мне было нужно. Конечно, могут быть и другие матчи, и я бы тоже хотел их вернуть.

Теперь, когда у меня есть подходящая модель json, функция сокращения выводит пустой словарь [:]. Это тип .reduce(into: [String:[String]](), который вызывает проблему?

Все данные печатаются, поэтому структура json и модели должна быть правильной.

* 1015 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 голосов
/ 24 января 2019

ОБНОВЛЕНИЕ Возможно, я ошибаюсь, что вы хотите получить.Ниже приведен еще один код, и, пожалуйста, проверьте результаты и выберите тот, который вы хотите.

Если вы хотите использовать 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"]]
0 голосов
/ 24 января 2019

Ваш код слишком сложный. Вы можете сгруппировать массив по 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}}
...