如何对Array Object Swift 4中的特定键求和?

时间:2018-08-27 14:50:38

标签: ios swift arrayobject

此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中,然后将其汇总。但是,它显示nil,但是当我在终端中将其写入时,它将分别给出值。我怎样才能将这个ArrayObject中的奖金相加?

此外,当我使用prizeArr = [String]()时,它可以工作并将奖品存储在数组中,但是对于Int,为什么它不起作用?

4 个答案:

答案 0 :(得分:1)

首先,正如@Benhamine指出的那样,您应该从一个干净的体系结构开始,并将JSON映射到类型安全的类中。

第1步:可编码类型

让我们定义一个表示我们的JSON的结构,以便我们可以更好地在我们的App中使用它。 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解码逻辑中进行。

无论如何,我们的想法是我们应该始终看待正在写的东西,并质疑如何改进

答案 1 :(得分:0)

let sum = winnerArr?[section]["response"].reduce(0, { x, y in
    x + y["prize"]
}) ?? 0

顺便说一句,我建议解析响应并将其变成可用的对象,而不是处理原始响应:https://developer.apple.com/swift/blog/?id=37

答案 2 :(得分:0)

尝试使用此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)
}

答案 3 :(得分:0)

感谢你们所有人的帮助。我是新手,不熟悉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