Как сложить определенный ключ в Array Object Swift 4? - PullRequest
0 голосов
/ 27 августа 2018

Этот ответ от API:

{
"status": 200,
"message": "Success",
"data": {
    "result": [
        {
            "name": "Anything",
            "response": [
                {
                    "name": "XYZ",
                    "prize": "1.86"
                },
                {
                    "name": "ABCD",
                    "prize": "9.86"
                }

            ]
        }
    ],
    "overall": "XYZ"
}
}

Как можно суммировать приз в ответе, как я должен показать его в заголовке таблицы. Я сделал это.

var prizeArr = [Int]()

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
    let header =  tableView.dequeueReusableHeaderFooterView(withIdentifier: cellReuseIdentifier) as! OverallHeaderCell

    let countArr = winnerArr![section]["response"] as? Array<Dictionary<String,Any>>

    prizeArr = (countArr!.compactMap{ $0["prize"] })

    print(prizeArr)

    header.textL[0].text = winnerArr![section]["name"] as? String
    header.textL[3].text = "\(String(describing: countArr!.count))"

    return header
}

Я пытаюсь сохранить prize в prizeArr, а затем подведу итоги. Но это печатает ноль, но когда я пишу это в терминале, это дает значение индивидуально. Как можно суммировать приз в этом ArrayObject?

Кроме того, когда я использую prizeArr = [String](), тогда он работает и сохраняет приз в массиве, но для Int почему он не работает?

Ответы [ 4 ]

0 голосов
/ 28 августа 2018

Спасибо всем вашим ребятам, которые помогли. Я новичок и не знаком с Codable. Спасибо, что познакомили меня с тем же. Я попытаюсь понять это и использовать это для будущих целей.

Итак, возвращаясь к ответу:

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
    {
    self.prizeArr.removeAll()

    let header =  tableView.dequeueReusableHeaderFooterView(withIdentifier: cellReuseIdentifier) as! OverallHeaderCell

    let resArr   = self.winnerArr![section]["response"]! as? Array<Dictionary<String,Any>>

    for prize in  resArr!
    {
        let doubleStr = prize["prize"] as? NSString

        self.prizeArr.append((doubleStr?.doubleValue)!)
    }

    let sumedArr = prizeArr.reduce(0, +)

    let countArr = winnerArr![section]["response"] as? Array<Dictionary<String,Any>>

    header.textL[0].text = winnerArr![section]["name"] as? String

    header.textL[1].text = "$\(sumedArr)"

    header.textL[3].text = "\(String(describing: countArr!.count))"

    return header
    }

Здесь я преобразовываю каждую строку в двойную и добавляю ее к prizeArr, а затем, наконец, суммирую весь массив, чтобы получить желаемый результат. Но это не идеальный способ сделать это. Этот ответ для всех новичков, как я, и, пожалуйста, изучите Codables.

0 голосов
/ 27 августа 2018

Попробуйте это Codable решение, чтобы уменьшить призы вместе:

struct Winners: Codable {
    let status: Int
    let message: String
    let data: DataClass
}

struct DataClass: Codable {
    let result: [Result]
    let overall: String
}

struct Result: Codable {
    let name: String
    let response: [Response]
}

class Response: Codable {
    let name: String
    let prize: Double

    init(name: String, prize: Double) {
        self.name = name
        self.prize = prize
    }

    enum CodingKeys: String, CodingKey {
        case name
        case prize
    }

    enum SerializationError: Error {
        case missing(String)
        case invalid(String, Any)
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)

        let prizeString = try container.decode(String.self, forKey: .prize)
        guard let prize = Double(prizeString) else {
            throw SerializationError.invalid("prize", prizeString)
        }

        self.prize = prize
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)
        try container.encode("\(prize)", forKey: .prize)
    }
}

func testing() {
    let winners = try! JSONDecoder().decode(Winners.self, from: jsonData)

    let sum = winners.data.result[section].response
        .map({ $0.prize })
        .reduce(0, +)
    print(sum)
}
0 голосов
/ 27 августа 2018

Во-первых, как заметил @Benhamine, вы должны начать с чистой архитектуры и отобразить свой JSON в класс безопасного типа.

Шаг 1: Кодируемые типы

Позволяет определить структуру, которая представляет наш JSON, чтобы мы могли лучше использовать его в нашем приложении. JSON - это то, что мы никогда не хотим распространять в нашем приложении. Давайте лучше обойдем что-то четко определенное и задокументированное, поэтому нам не нужно будет насильно разворачивать и вылетать из нашего приложения.

struct JSONResponse: Codable {
    enum CodingKeys: String, CodingKey {
        case data
    }
    let data: Data
}

extension JSONResponse {
    struct Data: Codable {

        enum CodingKeys: String, CodingKey {
            case results = "result"
        }

        let results: [Result]
    }
}

extension JSONResponse.Data {
    struct Result: Codable {
        let name: String
        let winners: [Winner]

        enum CodingKeys: String, CodingKey {
            case winners = "response"
            case name
        }
    }
}

extension JSONResponse.Data.Result {
    struct Winner: Codable {
        let name: String
        let prize: String
    }
}

Шаг 2: Разбор

Разбор с использованием Codable очень прост. Приведенный ниже код покажет, как мы конвертируем его в JSON, а также как можно получить сумму значений с плавающей запятой.

do {
    let o: JSONResponse = try JSONDecoder().decode(JSONResponse.self, from: jsonData)
    let floatValues = o.data.results.flatMap({ $0.winners }).compactMap({ Float($0.prize) })
    floatValues.reduce(0, +)
    print(floatValues)
} catch let e {
    print(e)
}

Шаг 3: интегрировать

Теперь у нас есть строительные блоки, которые нам нужны для получения этой информации, поэтому давайте подключим ее к вашему коду, начав с того, что мы хотим , чтобы наш код выглядел.

/// We store our main data type for easy reference
var resultsBySection: [Result]

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
    let header =  tableView.dequeueReusableHeaderFooterView(withIdentifier: cellReuseIdentifier) as! OverallHeaderCell

    let currentResults = resultsBySection[section]
    let prizeTotals = currentResults.flatMap({ $0.winners }).compactMap({ Float($0.prize) })
    let totalPriceMoney = prizeTotals.reduce(0, +)

    header.textL[0].text = currentResults.name
    header.textL[3].text = "\(String(describing: totalPriceMoney))"

    return header
}

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

Шаг 4: Рефакторинг

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

В нашем примере выше мы, вероятно, могли бы жестко закодировать итоги на контроллере или создать собственную структуру данных, которая сделает это за нас, когда мы проанализируем JSON. Всегда ли мы хотим вычислять итоги вручную, если нам всегда нужна эта сумма? У нас может быть специальная функция для вычисления или просто в нашей логике декодирования JSON.

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

0 голосов
/ 27 августа 2018
let sum = winnerArr?[section]["response"].reduce(0, { x, y in
    x + y["prize"]
}) ?? 0

Кроме того, я бы порекомендовал проанализировать ответ и превратить его в пригодные для использования объекты, а не иметь дело с необработанным ответом: https://developer.apple.com/swift/blog/?id=37

...