如何根据日期对json中的数据进行排序,并在swift中按日期求和?

问题描述 投票:0回答:2

我想根据日期和与日期匹配的名义数据量对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-03-30的总名义是300000 + 250000 = 550000

所以我得到的结果是:在2019-03-30总计是500000和2019-03-29总计是200000

请帮我

json swift sorting alamofire swifty-json
2个回答
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"
            }
        ]
    }
}

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)
            }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.