Сортировка "AllKeys" с отображением - PullRequest
0 голосов
/ 06 мая 2018

Я декодирую JSON с помощью динамических строковых ключей, который выглядит следующим образом:

{
"dynamickey1":
    {"infos1": "blabla","infos2": 21},
"dynamickey2":
    {"infos1": "blabla","infos2": 12},
... }

Они отсортированы так, как я хотел, так как я поместил список строк в URL. Но когда он декодирует словарь с кодом ниже (РЕДАКТИРОВАТЬ: я поставил полный код) , я потерял заказ:

struct Devise {
    let nom : String
    let EUR: Float
    let ETH: Float
}

struct DataPrix {
    let devises: [Devise]
    struct DataPrixCodingKeys: CodingKey {
        let stringValue : String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        var intValue : Int? {return nil}
        init?(intValue: Int) {return nil}
    }

    enum DeviseCodingKeys: String, CodingKey {
        case ETH
        case EUR
    }
}

let decoder = JSONDecoder()

extension DataPrix: Decodable {
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy : DataPrixCodingKeys.self)
        self.devises = try (container.allKeys).map { key in
            let devisesContainer = try container.nestedContainer(keyedBy: DeviseCodingKeys.self, forKey: key)
            let deviseName = key.stringValue
            let EUR  = try devisesContainer.decode(Float.self, forKey: .EUR)
            let ETH  = try devisesContainer.decode(Float.self, forKey: .ETH)
            return Devise(nom: deviseName, EUR: EUR, ETH: ETH)
        }
    }
}

Так можно ли отсортировать их по алфавиту на этом этапе или, по крайней мере, сохранить тот же порядок, который был в моем первоначальном списке?

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

Это скорее проблема с типом container. Кажется, вы используете NSDictionary, который имеет allKeys типа Any. Any не Comparable.

Самым простым решением является приведение словаря к [String: Any]. Затем вы можете напрямую использовать container.keys.sorted(), где < - компаратор по умолчанию.

let jsonString = """
{
  "dynamickey1": {"infos1": "blabla","infos2": 21},
  "dynamickey2": {"infos1": "blabla","infos2": 12}
}
"""

let jsonData = jsonString.data(using: .utf8)!
if let container = (try? JSONSerialization.jsonObject(with: jsonData, options: [])) as? [String: Any] {
    let sortedKeys = container.keys.sorted()
    print(sortedKeys)
}

Или переключитесь на использование протокола Codable и безопасно декодируйте тип JSON:

let jsonString = """
{
  "dynamickey1": {"infos1": "blabla","infos2": 21},
  "dynamickey2": {"infos1": "blabla","infos2": 12}
}
"""

let jsonData = jsonString.data(using: .utf8)!

struct Info: Codable {
    let infos1: String
    let infos2: Int
}

let parsed = try? JSONDecoder().decode([String: Info].self, from: jsonData)

if let container = parsed {
    print(container.keys.sorted())
}

РЕДАКТИРОВАТЬ Решение для обновленного вопроса:

let jsonString = """
{"XPR": {"EUR":0.6866,"ETH":0.001088}}
"""

let jsonData = jsonString.data(using: .utf8)!

enum Currency: String, CodingKey, Comparable {
    case XPR
    case EUR
    case ETH

    public static func < (lhs: Currency, rhs: Currency) -> Bool {
        return lhs.rawValue < rhs.rawValue
    }
}

struct Devise: Decodable {
    let name: String
    let rates: [Currency: Double]

    public init(from decoder: Decoder) throws {
        name = decoder.codingPath.last?.stringValue ?? ""
        let container = try decoder.container(keyedBy: Currency.self)

        var rates: [Currency: Double] = [:]
        try container.allKeys.forEach {
            rates[$0] = try container.decode(Double.self, forKey: $0)
        }
        self.rates = rates
    }
}

struct DataPrix: Decodable {
    let devises: [Devise]

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: Currency.self)
        devises = try container.allKeys.sorted().map {
            return try container.decode(Devise.self, forKey: $0)
        }
    }
}

let decoder = JSONDecoder()
do {
  let exchangeRates = try decoder.decode(DataPrix.self, from: jsonData)
  print(exchangeRates)
} catch {
  print(error)
}

Однако, если ваши ключи действительно динамические , вы не можете избежать словаря, и лучшим было бы просто использовать его:

let decoder = JSONDecoder()
do {
  let exchangeRates = try decoder.decode([String: [String: Double]].self, from: jsonData)
  print(exchangeRates)
} catch {
  print(error)
}
0 голосов
/ 06 мая 2018

Вы можете сортировать так:

let dictionary  = ["key1":"test","key0":"","key5":""]
dictionary.keys.sorted { $0.localizedCaseInsensitiveCompare($1) == ComparisonResult.orderedAscending }.map { key in
    // code
} 

так что для своего кода вы можете использовать вот так

  let keys = dic.keys.sorted { $0.localizedCaseInsensitiveCompare($1) == ComparisonResult.orderedAscending }
    print( keys.map { (key) -> [String : Devise]? in
        guard let value = dic[key] else {return nil}
        return [key : value]
        }.compactMap({$0}))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...