0

I want to sort the data from the json array according to the date, and the nominal amount of data that matches the date. I use swiftyjson and alamofire.

here is my code:

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)
                }
            }
        }

here is response 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",
}
]

what has been achieved:

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

i get data on 2019-03-30 are 2 nominal 300000 and 250000

in 2019-03-29 i get 1 nominal 200000

i want total nominal on 2019-03-30 are 300000 + 250000 = 550000

so the result should i get: on 2019-03-30 total is 500000 and 2019-03-29 total is 200000

please help me

1
  • I think u need to group the date, and then get total nominal for each date. For grouping the date, you can refer at here. Commented Apr 1, 2019 at 3:35

2 Answers 2

1

You should use Codable instead of SwiftyJSON as it's more explicitly typed but answering your question directly in regards to SwiftyJSON you could go with this:

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)
    }
}

Here, in processedTransactions(_:), we basically iterate through the dates and prepare unique entries based on just YYYY-DD-MM part.
Simultaneously we keep an account of the total sum of nominal value relating to a particular date.
This is done in the reduce part (The logic I have used is basic string manipulation but it can be argued that it's error pront so feel free to rewrite that part)
Then we sort it and just for better readability, we map to recreate the object as tuples (date: String, nominal: String)
We can then pass this to handleProcessedTransactions(_:) and operate required logic on it.


Also, you seem to be using UserDefaults so this is what the existing part of your code can look like:

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)
            }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

First Why you use SwiftyJSON and there is built in Codable protocol ? Tutorial

Second : The idea is to group your data by yyyy-MM-dd like that 2019-03-30 this will require more work . i create the decodable version for your response you can check

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
    }()
}

And you can use like that

 // (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 Response for above solution

{
    "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"
            }
        ]
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.