I have JSON array like this
var json = NSArray() // array with json objects
//print json >>
json = (
{
Name = "Alen";
Score = 500;
},
{
Name = "John";
Score = 0;
},
{
Name = "Mark";
Score = 2000;
},
{
Name = "Steve";
Score = 300;
},
{
Name = "Ricky";
Score = 900;
}
)
and i can access its objects as
(json[0] as! NSDictionary).object(forKey: "Name")
(json[0] as! NSDictionary).object(forKey: "Score")
I want to sort this JSON array according to scores.
I found the answers like
let sortedArray = json.sorted(by: { $0.0 < $1.0 })
which gives error
Value of type 'Any' has no member '0'
Then I tried this
let sortedArray = (json as! NSDictionary).sorted {(aDic, bDic) -> Bool in
return aDic.key < bDic.key
}
It gave error
Binary operator '<' cannot be applied to two 'Any' operands
Can you please guide me to sort the array according to score in swift 4?
That's a very good example why you are strongly discouraged from using NSArray
and NSDictionary
in Swift.
Both collection types don't provide type information so everything is treated as Any
. Most of the shared generic API of the Swift Standard library cannot be used with Any
so you are not able to take advantage of the powerful generic functions unless you add a lot of ugly type casts.
If all values are String
declare your array as
var json = [[String:String]]()
Then you can sort the array with
let sortedArray = json.sorted { $0["Score"]! < $1["Score"]! }
The most recommended solution is to decode the JSON directly into a custom struct
struct Player : Decodable {
let name : String
let score : String
private enum CodingKeys : String, CodingKey { case name = "Name", score = "Score" }
}
Then you get rid of all type casting and you can sort by the property name
var players = [Player]()
let jsonString = """
[{"Name" : "Alen", "Score" : "500"},
{"Name" : "John", "Score" : "0"},
{"Name" : "Mark", "Score" : "2000"},
{"Name" : "Steve", "Score" : "300"},
{"Name" : "Ricky", "Score" : "900"}]
"""
let data = Data(jsonString.utf8)
do {
players = try JSONDecoder().decode([Player].self, from: data)
let sortedPlayers = players.sorted{ $0.score.compare($1.score, options: .numeric) == .orderedAscending }
print(sortedPlayers)
} catch { print(error) }
Edit:
To load the JSON use an asynchronous way (URLSession
)
Never load data from a remote URL with synchronous Data(contentsOf
.
var players = [Player]()
let jsonUrl = URL(string: "url.json")!
let task = URLSession.shared.dataTask(with : url) { [unowned self] (data, _, error) in
if let error = error { print(error); return }
do {
players = try JSONDecoder().decode([Player].self, from: data!).sorted{ $0.score < $1.score }
DispatchQueue.main.async { // reload the table view if necessary
self.tableView.reloadData()
}
} catch { print(error) }
}
task.resume()