Reputation: 43
I am using swapi.co as my source of json data and my response looks like the following: https://swapi.co/api/people/
My array of "characters" has the structure
// MARK: - CharactersResult
struct CharactersResult: Codable {
let name, height, mass, hairColor: String
let skinColor, eyeColor, birthYear: String
let gender: Gender
let homeworld: String
let films, species, vehicles, starships: [String]
let created, edited: String
let url: String
enum CodingKeys: String, CodingKey {
case name, height, mass
case hairColor = "hair_color"
case skinColor = "skin_color"
case eyeColor = "eye_color"
case birthYear = "birth_year"
case gender, homeworld, films, species, vehicles, starships, created, edited, url
}
}
I would like to get the smallest character and the largest out of my array. My function is:
func getCharacters(urlToGet: String){
do{
if let url = URL(string: urlToGet) {
URLSession.shared.dataTask(with: url) { data, response, error in
if let data = data {
do {
let jsonCharacters = try JSONDecoder().decode(Characters.self, from: data)
self.characters = self.characters + jsonCharacters.results
self.nextPageUrlForCharacters = jsonCharacters.next
self.updatePicker()
} catch let error {
print(error)
}
}
}.resume()
}
}
}
My main question is where to do the sorting and what is the most efficient way to get the smallest and the largest character.
Upvotes: 2
Views: 99
Reputation: 285082
Assuming smallest and largest is related to the height of the character (then shortest and tallest are more appropriate), sort the array by that struct member. As the value is String
you have to add the .numeric
option.
The descending order starts with the largest value
let sortedCharacters = self.characters.sorted{$0.height.compare($1.height, options: .numeric) == .orderedDescending}
let tallestCharacter = sortedCharacters.first
let shortestCharacter = sortedCharacters.last
Side note: You can get rid of the CodingKeys if you add the convertFromSnakeCase
key decoding strategy.
Upvotes: 3
Reputation: 3817
This simplified version of your code illustrates how to sort by an arbitrary key, as long as that key is Comparable
(so I've made your height
and mass
properties both Int
s rather than String
):
struct MovieCharacter: Codable {
let name: String
let height: Int
let mass: Int
}
let fred = MovieCharacter(name: "Fred", height: 123, mass: 99)
let wilma = MovieCharacter(name: "Wilma", height: 158, mass: 47)
let chars = [fred, wilma]
let heaviestToLightest = chars.sorted { $0.mass > $1.mass }
// Prints "Fred, Wilma"
print(heaviestToLightest.map { $0.name }.joined(separator: ", "))
let tallestToShortest = chars.sorted { $0.height > $1.height }
// prints "Wilma, Fred"
print(tallestToShortest.map { $0.name }.joined(separator: ", "))
To change the sort order, reverse the >' in the comparison closure. If you want to know the "most" and "least" of a particular order, use
.firstand
.last` on the result.
Also, to save yourself from having to maintain the CodingKeys
enum, use .keyDecodingStrategy
of a JSONDecoder
:
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let characters = try decoder.decode(Characters.self, from: jsonData)
Upvotes: 0