How to append all elements from an element of JSON dictionary to an array with Alamofire and SwiftyJSON

我与影子孤独终老i 提交于 2019-12-11 17:09:38

问题


I am trying to append all closing prices from the most recent to the oldest available in a given JSON dictionary. The URL request that I'm using is the following:

https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=AMZN&interval=60min&outputsize=full&apikey=5H2L6THH6BSCAMKO

As you can see, the result is a dictionary ordered with the most recent dates and within that dictionary, there is various options, including the closing price. A little bit of it can be seen below.

{
"Meta Data": {
    "1. Information": "Intraday (60min) open, high, low, close prices and volume",
    "2. Symbol": "AMZN",
    "3. Last Refreshed": "2018-08-15 12:30:00",
    "4. Interval": "60min",
    "5. Output Size": "Full size",
    "6. Time Zone": "US/Eastern"
},
"Time Series (60min)": {
    "2018-08-15 12:30:00": {
        "1. open": "1892.1620",
        "2. high": "1898.0000",
        "3. low": "1879.3600",
        "4. close": "1892.5000",
        "5. volume": "893752"
    },
    "2018-08-15 11:30:00": {
        "1. open": "1873.4399",
        "2. high": "1893.3500",
        "3. low": "1873.4399",
        "4. close": "1892.1200",
        "5. volume": "798959"
    },
    "2018-08-15 10:30:00": {
        "1. open": "1905.1899",
        "2. high": "1915.5300",
        "3. low": "1871.0200",
        "4. close": "1871.0200",
        "5. volume": "1614045"
    },

Now, I want to append, from the most recent date and below it in order, the closing price. I've tried to use a for loop, while loops and playing a bit with the Date structure to successfully request the closing price of each date in an orderly fashion, however it gets stuck when I try to access a former date. The function I am using is the following one.

    func get1HPriceArr(stock:String, dataPoints:Int){


    let url = "https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=\(stock)&interval=60min&outputsize=full&apikey=5H2L6THH6BSCAMKO"


    Alamofire.request(url, method: .get).validate().responseJSON { response in
        switch response.result  {
        case .success(let value):



            let timeZone = TimeZone(secondsFromGMT: 0000)

            let dateFormatter = DateFormatter()

            dateFormatter.timeZone = timeZone!


            dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

            let json = JSON(value)

            var DatesArray:[String] = []

            var ClosingPrices:[Double] = []

            var followingDate:String?

            func AddDates() -> [Double]{

                print("FollowingDate just below the func  is \(followingDate)")

                while ClosingPrices.count != dataPoints {


                    print("Following date in the while loop is \(followingDate)")


                    let mostRecentRefreshed = json["Meta Data"]["3. Last Refreshed"].stringValue

                    print("Most recent refreshed is \(mostRecentRefreshed)")

                    if followingDate == nil {

                        followingDate = mostRecentRefreshed

                        let closingPrice = json["Time Series (60min)"][followingDate!]["4. close"].doubleValue

                        print("Following Date was nil and now its value is \(followingDate!)")
                        DatesArray.append(followingDate!)
                        ClosingPrices.append(closingPrice)

                        print(ClosingPrices)


                        // You must check if most recent refreshed is 16:00

                        let followingDateDate = dateFormatter.date(from: followingDate!)

                        let hour = Calendar.current.component(.hour, from: followingDateDate!)

                        let minutes = Calendar.current.component(.minute, from: followingDateDate!)

                        if hour == 16{


                            let halfNHourMore = Calendar.current.date(byAdding: .minute,value: 30, to: followingDateDate!)

                            let dateStringNil = dateFormatter.string(from: halfNHourMore!)

                            followingDate = dateStringNil


                        } else {

                            print("Last refreshed time is not 16:00, so following date was nil and now is \(followingDate)")

                        }

                    }

                    print("Following date is \(String(describing: followingDate))")

                    var currentDate = dateFormatter.date(from: followingDate!)

                    print("Current Date is \(currentDate)")

                    let dateHour = Calendar.current.component(.hour, from: currentDate!)

                    let dateMinutes = Calendar.current.component(.minute, from: currentDate!)

                    var oneHourLess:Date!

                    if dateHour == 16 && dateMinutes == 0 {

                        oneHourLess = Calendar.current.date(byAdding: .minute,value: -30, to: currentDate!)

                    } else {

                        oneHourLess = Calendar.current.date(byAdding: .hour,value: -1, to: currentDate!)

                    }



                    let dateString = dateFormatter.string(from: oneHourLess!)

                    if (dateString.contains("17:30:00")) || (dateString.contains("18:30:00")) || (dateString.contains("19:30:00")) || (dateString.contains("20:30:00")) || (dateString.contains("21:30:00")) || (dateString.contains("22:30:00")) || (dateString.contains("23:30:00")) || (dateString.contains("00:30:00")) || (dateString.contains("01:30:00")) || (dateString.contains("02:30:00")) || (dateString.contains("03:30:00")) || (dateString.contains("04:30:00")) || (dateString.contains("05:30:00")) || dateString.contains("06:30:00") || dateString.contains("05:30:)0") || dateString.contains("06:30:00") || dateString.contains("07:30:00") || dateString.contains("08:30:00") || dateString.contains("09:30:00") {

                        print("OneHourLess is \(oneHourLess)")

                        print("Its closing time since the time is \(dateString)")

                    } else {


                        DatesArray.append(dateString)

                        followingDate = dateString

                        print("Following date is \(String(describing: followingDate))")

                        currentDate = dateFormatter.date(from: followingDate!)

                        let closingPrice = json["Time Series (60min)"][followingDate!]["4. close"].doubleValue

                        let weekday = Calendar.current.component(.weekday, from: currentDate!)

                        let hour = Calendar.current.component(.hour, from: currentDate!)

                        let minutes = Calendar.current.component(.minute, from: currentDate!)

                        print("Weekday is \(weekday)")

                        print("Hour is \(hour)h")

                        print("Minutes are \(minutes)min")

                        ClosingPrices.append(closingPrice)
                        print("Closing prices count is \(ClosingPrices.count)")
                        print("Closing prices array is \(ClosingPrices)")



                        let oneDayLess = Calendar.current.date(byAdding: .day,value: -1, to: currentDate!)
                        let oneDayLessString = dateFormatter.string(from: oneDayLess!)
                        followingDate = oneDayLessString

                        print("Following date minus one day is \(followingDate)")




                    }












                }

                print(DatesArray)
                print("Closing prices are \(ClosingPrices)")

                return ClosingPrices


            }

            AddDates()


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

    }

} // End of get1HPriceArr()

Is there any way to append all elements from the array (In the same order as the api gives) without having to pass in the date programatically by myself? Or is any other way I could achieve the same result?


回答1:


This is a standalone suggestion with Decodable. It's much more versatile than SwiftyJSON. You can test it in a Playground.

The result is an array of struct Price sorted by date descending. An array is preferable because a dictionary is unordered.

The JSON

let jsonString = """
{
"Meta Data": {
"1. Information": "Intraday (60min) open, high, low, close prices and volume",
"2. Symbol": "AMZN",
"3. Last Refreshed": "2018-08-15 12:30:00",
"4. Interval": "60min",
"5. Output Size": "Full size",
"6. Time Zone": "US/Eastern"
},
"Time Series (60min)": {
    "2018-08-15 12:30:00": {
    "1. open": "1892.1620",
    "2. high": "1898.0000",
    "3. low": "1879.3600",
    "4. close": "1892.5000",
    "5. volume": "893752"
    },
    "2018-08-15 11:30:00": {
    "1. open": "1873.4399",
    "2. high": "1893.3500",
    "3. low": "1873.4399",
    "4. close": "1892.1200",
    "5. volume": "798959"
    },
    "2018-08-15 10:30:00": {
    "1. open": "1905.1899",
    "2. high": "1915.5300",
    "3. low": "1871.0200",
    "4. close": "1871.0200",
    "5. volume": "1614045"
    }
    }
}
"""

The structs

struct Stocks: Decodable {

    enum  CodingKeys: String, CodingKey { case timeSeries = "Time Series (60min)"}

    struct TimeSerie: Decodable {
        let close : String

        enum  CodingKeys: String, CodingKey { case close = "4. close" }
    }

    let timeSeries : [String:TimeSerie]
}

struct Price {
    let date : Date
    let price : Double
}

The parsing

let data = Data(jsonString.utf8)   
let decoder = JSONDecoder()

let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
do {
    let stocks = try decoder.decode(Stocks.self, from: data)
    let result = stocks.timeSeries.map { (key: String, value: Stocks.TimeSerie) -> Price in
        return Price(date: dateFormatter.date(from: key)!, price: Double(value.close)!)
    }.sorted(by: {$0.date > $1.date})

    print(result)
} catch { print(error) }


来源:https://stackoverflow.com/questions/51863329/how-to-append-all-elements-from-an-element-of-json-dictionary-to-an-array-with-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!