47977


swift4を使い、以下で公開されているAPIを使ってJSONを取得しました  
しかしKeyが数値で返されるのでどうやってパースしたら良いかわかりません。

<https://cryptowatch.jp/docs/api>

取得できるJSONデータの形式

[code]

    {
      "result": {
        "60": [
          [1481634360, 782.14, 782.14, 781.13, 781.13, 1.92525],
          [1481634420, 782.02, 782.06, 781.94, 781.98, 2.37578],
          [1481634480, 781.39, 781.94, 781.15, 781.94, 1.68882]
        ]
      }
    }
    
[/code]

ここで欲しいのはkey”60”以下のデータなのですが、どのように取り出せば良いのでしょうか？


CC BY-SA 4.0
2018-08-31T08:13:26.197
47973
2018-08-31T11:23:45.133
2018-08-31T08:28:56.423
3060
29936
question
json swift4
swiftで数値をKeyにもつJSONデータをパース


「数値をKeyに持つ」とは言っても、正しく引用符で囲まれていますから正当なJSONデータということになります。`JSONSerialization`でも、Swift
4から登場した`Codable`でも読み込むことはできますが、タグでswift4が指定されていることでもあり、ここでは`Codable`を使った例を示しておきます。

「自分でここまではやったのだが、この部分がうまくできない」と言うのを(動かないコードでも良いので)コードを示して質問されると、より的確な回答をより早く得ることにつながります。今後ご質問を書かれる際にはご留意ください。

さて、リンク先に挙げられたAPIの解説によると、キーになりうる値は限られているようです。

>
[code]

>     All periods supported:
>  
>      Value    Label
>      ------   -----
>      60        1m
>      180       3m
>      300       5m
>      900       15m
>      1800      30m
>      3600      1h
>      7200      2h
>      14400     4h
>      21600     6h
>      43200     12h
>      86400     1d
>      259200    3d
>      604800    1w
>  
[/code]

まずはSwiftの識別子として有効な名前でそれらに対応するプロパティを持つ`struct`を定義します。同時にJSON中のKeyとそれらのプロパティを対応づけるために`CodingKeys`と言うものを一緒に宣言しておきます。

[code]

    typealias ResultValues = [[Double]]
    struct PeriodicResults: Codable {
        var p1m: ResultValues?
        var p3m: ResultValues?
        var p5m: ResultValues?
        var p15m: ResultValues?
        var p30m: ResultValues?
        var p1h: ResultValues?
        var p2h: ResultValues?
        var p4h: ResultValues?
        var p6h: ResultValues?
        var p12h: ResultValues?
        var p1d: ResultValues?
        var p3d: ResultValues?
        var p1w: ResultValues?
    
        private enum CodingKeys: String, CodingKey {
            case p1m = "60" //<- `p1m`には、"60": ... に対応する値が入る
            case p3m = "180"
            case p5m = "300"
            case p15m = "900"
            case p30m = "1800"
            case p1h = "3600"
            case p2h = "7200"
            case p4h = "14400"
            case p6h = "21600"
            case p12h = "43200"
            case p1d = "86400"
            case p3d = "259200"
            case p1w = "604800"
        }
    }
    
[/code]

これを使って、結果全体を表す`struct`を作ると、こんな感じになります。テスト用のサンプルデータとともに示しておきます。

[code]

    import Foundation
    
    let jsonText = """
    {
        "result": {
            "60": [
                [1481634360, 782.14, 782.14, 781.13, 781.13, 1.92525],
                [1481634420, 782.02, 782.06, 781.94, 781.98, 2.37578],
                [1481634480, 781.39, 781.94, 781.15, 781.94, 1.68882]
            ]
        }
    }
    """
    let jsonData = jsonText.data(using: .utf8)!
    
    
    struct OHLCResult: Codable {
        var result: PeriodicResults
    }
    
    do {
        let ohlcResult = try JSONDecoder().decode(OHLCResult.self, from: jsonData)
        if let p1m = ohlcResult.result.p1m {
            for valueSet in p1m {
                print(valueSet)
            }
        } else {
            print("no data for \"60\"")
        }
    } catch {
        print(error)
    }
    
[/code]

出力:

>
[code]

>     [1481634360.0, 782.13999999999999, 782.13999999999999, 781.13, 781.13,
> 1.9252499999999999]
>     [1481634420.0, 782.01999999999998, 782.05999999999995,
> 781.94000000000005, 781.98000000000002, 2.3757799999999998]
>     [1481634480.0, 781.38999999999999, 781.94000000000005,
> 781.14999999999998, 781.94000000000005, 1.68882]
>  
[/code]

(出力される値がJSON内の表現とは異なっていますが、これは`Double`を使う上で避けられません。ユーザに見せる情報を作る場合には必要に応じて書式化してください。)

* * *

なお、Keyになりうる値は実は他にもある、と言う場合には、`Dictionary`型を使った方がいいでしょう。こんな感じになります。

[code]

    struct OHLCDicResult: Codable {
        var result: [String: ResultValues]
    }
    
    do {
        let ohlcDicResult = try JSONDecoder().decode(OHLCDicResult.self, from: jsonData)
        if let p1m = ohlcDicResult.result["60"] {   //<-辞書型なので[]を使って元のキーを文字列としてそのまま使う
            for valueSet in p1m {
                print(valueSet)
            }
        } else {
            print("no data for \"60\"")
        }
    } catch {
        print(error)
    }
    
[/code]

出力例は先ほどと全く同じになります。お好きな方をお試しください。


CC BY-SA 4.0
2018-08-31T11:23:45.133
47977
2018-08-31T11:23:45.133
13972
47973
answer