使用奇怪的 JSON 文件格式查找汇率键值

Posted

技术标签:

【中文标题】使用奇怪的 JSON 文件格式查找汇率键值【英文标题】:Exchange Rate Key Value Lookup With Weird JSON File Format 【发布时间】:2021-04-27 15:12:48 【问题描述】:

在给定密钥(3 位货币代码)的情况下,我需要查找货币汇率方面的帮助。 JSON 对象非常不寻常,没有日期、时间戳、成功或速率等标签。第一个字符串值是基础货币或本国货币。在下面的示例中,它是“usd”(美元)。

我想通过给出其 3 位货币代码并将其存储在有序数组中来遍历所有货币以获取每种汇率。


    "usd": 
        "aed": 4.420217,
        "afn": 93.3213,
        "all": 123.104693,
        "amd": 628.026474,
        "ang": 2.159569,
        "aoa": 791.552347,
        "ars": 111.887966,
        "aud": 1.558363,
        "awg": 2.164862,
        "azn": 2.045728,
        "bam": 1.9541,
        "bbd": 2.429065,
        "bch": 0.001278
    

在格式稍有不同的 JSON 对象中,我使用以下循环将汇率复制到有序数组。

 for index in 0..<userData.rateArray.count 
      currencyCode = currCode[index]
                   
           if let unwrapped = results.rates[currencyCode] 
                  userData.rateArray[index]   = 1.0 / unwrapped
           
      

以下代码是用于获取 3 位货币代码和汇率的 API(通过 UpdateRates 调用)。

class GetCurrency: Codable 
    
    let id = UUID()
    var getCurrencies: [String : [String: Double]] = [:]
    
    required public init(from decoder: Decoder) throws 
        do
            print(#function)
            let baseContainer = try decoder.singleValueContainer()
            let base = try baseContainer.decode([String : [String: Double]].self)
            for key in base.keys
                getCurrencies[key] = base[key]
            
        catch
            print(error)
            throw error
        
    



class CurrencyViewModel: ObservableObject
    
    @Published var results: GetCurrency?
    @Published var selectedBaseCurrency: String = "usd"
        
    func UpdateRates() 
        
        let baseUrl = "https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies/"
        let baseCur = selectedBaseCurrency   // usd, eur, cad, etc
        let requestType = ".json"
        
        guard let url = URL(string: baseUrl + baseCur + requestType) else 
            print("Invalid URL")
            return
        
        let request = URLRequest(url: url)

        URLSession.shared.dataTask(with: request)  data, response, error in
            if let data = data 
                do
                    let decodedResponse = try JSONDecoder().decode(GetCurrency.self, from: data)
                    
                    DispatchQueue.main.async 
                    self.results = decodedResponse
                         
                        // this prints out the complete table of currency code and exchange rates
                        print(self.results?.getCurrencies["usd"] ?? 0.0)
                       
                    
                 catch 
                    //Error thrown by a try
                    print(error)//much more informative than error?.localizedDescription
                
            
            if error != nil 
                //data task error
                print(error!)
            
        .resume()
    

【问题讨论】:

如果您已经拥有“usd”,self.results?.getCurrencies["usd"]?.keys 会在您将其放入循环时为您提供其余货币的 3 个字母代码/密钥。如果您将UpdateRates() 更改为func UpdateRates(baseCurrency: String) 以接收参数并将其更改为使用参数let baseCur = baseCurrency,您可以在循环中调用UpdateRates(baseCurrency: key) 我在调用 UpdateRates: .onAppear(perform: vm.UpdateRates(baseCur: baseCurrency.baseCur.baseS)) 时遇到问题。它给出错误无法将类型“()”的值转换为预期的参数类型“(()-> Void)?”为了防止与我的基础货币结构混淆,我将传递给 UpdateRates 的参数更改为 baseCur。存储在结构体baseCurrency.baseCur和baseS中的系统基础货币是基础货币3位字符串。 您缺少一些括号,使 onAppear 方法类似于我在上一个问题中使用的方法。 好的,我让 onAppear 工作了;我看到它不需要 perform 关键字。在 UpdateRates 我可以打印(self.results?getCurrencies[baseCur]?.values ?? 0.0) 它给了我一个大表baseCur基础货币的汇率。那么如何使用 3 位货币代码迭代这些值以获得给定键的单个值? 你遍历键看看第一条评论 【参考方案1】:

感谢 lorem ipsum 的帮助。下面是更新的 ASI 逻辑,它使用键/值查找将汇率复制到 rateArray。

class CurrencyViewModel: ObservableObject
    
    @Published var results: GetCurrency?
    @Published var rateArray = [Double] ()
    
    init() 
        if UserDefaults.standard.array(forKey: "rates") != nil 
            rateArray = UserDefaults.standard.array(forKey: "rates") as! [Double]
        else 
            rateArray = [Double] (repeating: 0.0, count: 160)
            UserDefaults.standard.set(self.rateArray, forKey: "rates")
        
    
    
    func updateRates(baseCur: String) 
        
            ...

                    DispatchQueue.main.async 
                        self.results = decodedResponse
                        
                        // loop through all available currencies
                        for index in 0..<currCode.count 
                            currencyCode = currCode[index]
                            
                            // spacial handling for base currency
                            if currencyCode == baseCur 
                                self.rateArray[index] = 1.0000
                             else 
                                
                                let homeRate = self.results?.getCurrencies[baseCur]
                        
                                // complement and save the exchange rate
                                if let unwrapped = homeRate?[currencyCode] 
                                    self.rateArray[index] = 1.0 / unwrapped
                                
                            
                        
                    
                 catch 
                    //Error thrown by a try
                    print(error)//much more informative than error?.localizedDescription
                
            
            if error != nil 
                //data task error
                print(error!)
            
        .resume()
    

【讨论】:

以上是关于使用奇怪的 JSON 文件格式查找汇率键值的主要内容,如果未能解决你的问题,请参考以下文章

在所有文件中找到JSON键,并删除相应的键值对。

Python将JSON格式文件导入 redis,多种方法

Python将JSON格式文件导入 redis,多种方法

使用 shell 脚本迭代 json 以存储键值对

雅虎汇率不起作用

如何将CSV格式转换成JSON格式