如何根据日期对json中的数据进行排序,并按日期对名义数据进行快速汇总?

时间:2019-04-01 03:20:27

标签: json swift sorting alamofire swifty-json

我想根据日期对json数组中的数据进行排序, 以及与日期匹配的名义数据量。我使用swiftyjson和alamofire。

这是我的代码:

import UIKit
import Alamofire
import SwiftyJSON

    class HomeViewController: UIViewController{
          override func viewDidLoad() {
            super.viewDidLoad()
             fetchData()

             let createOrder = UserDefaults.standard.stringArray(forKey: "createOrder")
             let nominal = UserDefaults.standard.stringArray(forKey: "nominal")

             createOrder = createOrder?.sorted{ $0 < $1 } 
             print(createOrder?.description)
           }
         }

    func fetchData(){
            let url = ""

            Alamofire.request(url, method: .get, encoding: URLEncoding.default).responseJSON{
                (response) in
                switch response.result {

                case .success(let value):
                    let json = JSON(value)
                    print(json)

                    let jsonData = json["data"]["transaction"]

                    let data = jsonData.arrayValue.map{ $0["nominal"].string}
                    let createOrder = jsonData.arrayValue.map { $0["order_created"].string}

                    UserDefaults.standard.set(data, forKey: "nominal")
                    UserDefaults.standard.set(createOrder, forKey: "createOrder")

                case .failure(let error):
                    print(error)
                }
            }
        }

这是响应JSON

"data" : {
    "transaction" : [

{
    "order_created" : "2019-03-30 14:39:05",
    "nominal" : "300000",
},
{
    "order_created" : "2019-03-30 11:26:08",
    "nominal" : "250000",
},
{
    "order_created" : "2019-03-29 10:49:44",
    "nominal" : "200000",
}
]

已取得的成就:

Optional("[\"2019-03-30 10:49:44\", \"2019-03-30 11:26:08\", \"2019-03-30 14:39:05\"]")

我在2019-03-30上获得的数据是2个名义上的300000和250000

在2019-03-29中,我得到1名义价值200000

我希望2019年3月30日的总名义金额为300000 + 250000 = 550000

所以结果我应该得到: 于2019-03-30总计500000 并且2019-03-29总计为200000

请帮助我

2 个答案:

答案 0 :(得分:0)

首先为什么使用SwiftyJSON并且内置Codable protocolTutorial

第二:这个想法是像yyyy-MM-dd那样按2019-03-30对数据进行分组,这将需要更多工作。我为您的回复创建了可解码的版本,您可以检查

import Foundation

struct JsonData: Decodable {
    let data: Transactions
}
struct Transactions: Decodable {
    let transaction: [Transaction]
}

struct Transaction: Decodable {
    let nominal: String
    let orderCreated : Date

    enum CodingKeys: String, CodingKey {
        case orderCreated = "order_created"
        case nominal
    }
}

extension JsonData {
    init(data: Data) throws {
        self = try DatedDecoder().decode(JsonData.self, from: data)
    }
}

fileprivate func DatedDecoder() -> JSONDecoder {
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .formatted(DateFormatter.yyyyMMddHHmmss)
    return decoder
}


extension DateFormatter {


    // for modeling json data
    static let yyyyMMddHHmmss : DateFormatter = {
        let dateFormater = DateFormatter()
        dateFormater.dateFormat = "yyyy-MM-dd HH:mm:ss"
        dateFormater.timeZone = TimeZone(abbreviation: "UTC")
        dateFormater.locale = Locale(identifier: "en_US_POSIX")
        return dateFormater
    }()

    // for grouping
    static let yyyyMMdd: DateFormatter = {
        let dateFormater = DateFormatter()
        dateFormater.dateFormat = "yyyy-MM-dd"
        dateFormater.timeZone = TimeZone(abbreviation: "UTC")
        dateFormater.locale = Locale(identifier: "en_US_POSIX")
        return dateFormater
    }()
}

您可以使用

 // (data) is response of your API call

 if let jsonData = try? JsonData(data: data){

            let predicate: (Transaction) -> String = { transaction in
                return DateFormatter.yyyyMMdd.string(from: transaction.orderCreated)
            }

            let groupingByDate : [String:[Transaction]] = Dictionary(grouping: jsonData.data.transaction, by: predicate)

            let items =  groupingByDate.map { item -> (date:String , value:Int) in
               return (item.key , item.value.map({Int(String($0.nominal))!}).reduce(0, +))
            }
            //  Final Items array is tuple with date and total nominal  [(date: "2019-03-30", value: 550000), (date: "2019-03-29", value: 200000)
            print(items)
        }

上述解决方案的Json API响应

{
    "data" : {
        "transaction" : [

            {
                "order_created" : "2019-03-30 14:39:05",
                "nominal" : "300000"
            },
            {
                "order_created" : "2019-03-30 11:26:08",
                "nominal" : "250000"
            },
            {
                "order_created" : "2019-03-29 10:49:44",
                "nominal" : "200000"
            }
        ]
    }
}

答案 1 :(得分:0)

您应该使用Codable而不是SwiftyJSON,因为它的输入更明确,但是直接回答关于SwiftyJSON的问题,您可以这样做:

func processedTransactions(_ transactions: JSON) -> [(date: String, nominal: Double)] {
    let processedTransactions = transactions
        .arrayValue
        .reduce(into: [String: Double]()) { (r, t) in
            if let date = t["order_created"].stringValue.split(separator: " ").first {
                let date = String(date)
                r[date] = r[date, default: 0] + (Double(t["nominal"].stringValue) ?? 0)
            }
        }
        .sorted { $0.key > $1.key }
        .map { (date: $0.key, nominal: $0.value) }

    return processedTransactions
}

func handleProcessedTransactions(_ transactions: [(date: String, nominal: Double)]) {
    //do something with your sorted transactions
    for t in transactions {
        print(t.date, t.nominal)
    }
}

这里,在processedTransactions(_:)中,我们基本上遍历日期并仅基于YYYY-DD-MM部分准备唯一的条目。
同时,我们记下与特定日期有关的名义价值的总和。
这是在reduce部分完成的(我使用的逻辑是基本的字符串操作,但可以说它是错误的,所以可以随时重写该部分
然后我们sort,为了更好的可读性,我们map将对象重新创建为元组(date: String, nominal: String)
然后,我们可以将其传递给handleProcessedTransactions(_:)并对其进行所需的逻辑。


此外,您似乎正在使用UserDefaults,因此代码的现有部分可能如下所示:

override func viewDidLoad() {
    super.viewDidLoad()
    fetchData()

    let json = UserDefaults.standard.object(forKey: "transactions")
    let transactions = processedTransactions(JSON(json))
    handleProcessedTransactions(transactions)
}

func fetchData() {
    let url = ""
    Alamofire
        .request(url, method: .get, encoding: JSONEncoding.default)
        .responseJSON { (response) in
            switch response.result {
            case .success(let value):
                let json = JSON(value)

                let transactionJSON = json["data"]["transaction"]
                UserDefaults.standard.set(transactionJSON.arrayObject, forKey: "transactions")

                //you probably want to handle it here too
                let transactions = self.processedTransactions(transactionJSON)
                self.handleProcessedTransactions(transactions)
            case .failure(let error):
                print(error)
            }
    }
}