如何从Moya.Response查询返回的对象中解析嵌套的JSON数组

时间:2019-04-03 10:34:52

标签: json swift parsing codable moya

我正在尝试解析网络会话(通过MoyaProvider完成)导致的JSON对象。返回的JSON对象中嵌套了JSON数组。看起来像这样:

  

编辑:链接到json文件在这里。 results.json

#%%
# imports
import datetime, time
import pandas as pd
import numpy as np
import statsmodels.api as sm
from collections import OrderedDict

# your data in a more easily reprodicible format
data = {'Date': ['2019-03-31 08:59:59.999', '2019-03-31 09:59:59.999', '2019-03-31 10:59:59.999',
        '2019-03-31 11:59:59.999',  '2019-03-31 12:59:59.999', '2019-03-31 13:59:59.999',
        '2019-03-31 14:59:59.999', '2019-03-31 15:59:59.999', '2019-03-31 16:59:59.999'],
        'Price': [1660, 1657, 1656, 1652, 1646, 1645, 1650, 1669, 1674]}

# function to make a useful time structure as independent variable
def myTime(date_time_str):
    date_time_obj = datetime.datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S.%f')
    return(time.mktime(date_time_obj.timetuple()))

# add time structure to dataset
data['Time'] = [myTime(obs) for obs in data['Date']]

# time for pandas
df = pd.DataFrame(data)

# Function for rolling OLS of a desired window size on a pandas dataframe

def RegressionRoll(df, subset, dependent, independent, const, win):
    """
    RegressionRoll takes a dataframe, makes a subset of the data if you like,
    and runs a series of regressions with a specified window length, and
    returns a dataframe with BETA or R^2 for each window split of the data.

    Parameters:
    ===========
    df -- pandas dataframe
    subset -- integer - has to be smaller than the size of the df or 0 if no subset.
    dependent -- string that specifies name of denpendent variable
    independent -- LIST of strings that specifies name of indenpendent variables
    const -- boolean - whether or not to include a constant term
    win -- integer - window length of each model

    Example:
    ========
    df_rolling = RegressionRoll(df=df, subset = 0, 
                                dependent = 'Price', independent = ['Time'],
                                const = False, win = 3)

    """

    # Data subset
    if subset != 0:
        df = df.tail(subset)
    else:
        df = df

    # Loopinfo
    end = df.shape[0]+1
    win = win
    rng = np.arange(start = win, stop = end, step = 1)

    # Subset and store dataframes
    frames = {}
    n = 1

    for i in rng:
        df_temp = df.iloc[:i].tail(win)
        newname = 'df' + str(n)
        frames.update({newname: df_temp})
        n += 1

    # Analysis on subsets
    df_results = pd.DataFrame()
    for frame in frames:

    #debug
    #print(frames[frame])

    # Rolling data frames
    dfr = frames[frame]
    y = dependent
    x = independent

    # Model with or without constant
    if const == True:
        x = sm.add_constant(dfr[x])
        model = sm.OLS(dfr[y], x).fit()
    else:
        model = sm.OLS(dfr[y], dfr[x]).fit()

    # Retrieve price and price prediction
    Prediction = model.predict()[-1]
    d = {'Price':dfr['Price'].iloc[-1], 'Predict':Prediction}
    df_prediction = pd.DataFrame(d, index = dfr['Date'][-1:])

    # Retrieve parameters (constant and slope, or slope only)
    theParams = model.params[0:]
    coefs = theParams.to_frame()
    df_temp = pd.DataFrame(coefs.T)
    df_temp.index = dfr['Date'][-1:]

    # Build dataframe with Price, Prediction and Slope (+constant if desired)
    df_temp2 = pd.concat([df_prediction, df_temp], axis = 1)
    df_temp2=df_temp2.rename(columns = {'Time':'Slope'})
    df_results = pd.concat([df_results, df_temp2], axis = 0)

return(df_results)

# test run
df_rolling = RegressionRoll(df=df, subset = 0, 
                            dependent = 'Price', independent = ['Time'],
                            const = False, win = 3)
print(df_rolling)

现在使用Moya,我可以通过使用Moya.Response API来获取数据:

{
“resultCount” : 50,
“results” :
[
    {
        “data1”: 1
        “data2”: 2
    },
    {
        “data1”: 1
        “data2”: 2
    },
    {
        “data1”: 1
        “data2”: 2
    }
]
}

但是我不想这样做,我想将其映射到我的Model结构。我在下面做了这样的事情。我已经通过OPTION + MouseHover检查了objMovie的类型为[Movie]

let jsonObj = try response.mapJSON()

我已经使用类似的技术在线上了一个教程,但是我 不明白为什么objMovie为什么不包含执行以上行后的返回值。我尝试做

let objMovie = try response.map(ITunesSearchResults<Movie>.self).results

但控制台上没有任何显示。

那有什么用?

以下是一些代码段。 ITunesSearchResults在哪里:

print(obj.< propertyofMovie >)

我的电影结构是这样。它符合JSON嵌套数组属性中找到的键值。

struct ITunesSearchResults<T: Decodable>: Decodable {
    let results: [T]
}

1 个答案:

答案 0 :(得分:0)

首先,当您想要使用Data对JSON进行解码时,请使用Moya的{​​{1}}响应

Decodable

您的let data = response.data 结构太复杂了,显式Movie并且根本不需要CodingKeys方法,您可以免费获得它们。足够了:

init

请注意,struct ITunesSearchResults<T: Decodable>: Decodable { let results: [T] } struct Movie: Decodable { let trackId: Int let trackName: String let trackGenre: String? let trackPrice: Double? let longDescription: String } trackPriceDoubletrackGenre是可选的。

现在只需解码

trackPrice

注意:

从不使用

之类的语法
do {
    let result = try JSONDecoder().decode(ITunesSearchResults<Movie>.self, from: data)
    print(result)
} catch { print(error) }

try container.decode(Int?.self, forKey: .trackPrice)

decodeIfPresent

巨大的好处是,如果存在密钥,但是类型错误,例如在这种具体情况下,它将引发错误。