0

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?

5
  • 2
    Title of the question is Swift 4 and taggued with Swift 3, strange. Also, avoid using NSDictionary/NSArra in Swift, use Swift Dictionary/Array, event better: avoid NSStuff when available in Swift 3. Commented Apr 25, 2018 at 8:21
  • var json is not JSON so far, it is just an NSArray of NSDictionary. As @Larme mentioned, you should avoid using these guys if you could, go with native Swift collections (for instance [[String: Int]]). Commented Apr 25, 2018 at 8:23
  • And looks like you forgot to convert your dictionaries into objects (using structs or classes) which would greatly help managing this data. You should avoid using JSON and dictionaries directly, better use model objects. Commented Apr 25, 2018 at 8:36
  • sorry I am very new to swift, I have no idea how to do that.. Commented Apr 25, 2018 at 9:57
  • @FaizyZaidy Look at vadian's answer. Commented Apr 25, 2018 at 10:05

5 Answers 5

1

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()
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks alott @vadian This helped me alot, I am sorry I am new to swift, and I was getting my Json file like this let jsonUrl = URL(string: "url.json") do { let data = try Data(contentsOf: jsonUrl!) //let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary json = try (JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.mutableContainers) as? NSArray)! would you suggest anything on this?
Thanks @Vadian I did exactly same but while printing players it says (CodingKeys in _D02FB714673388A51EFFF7A36D0361B0).score], debugDescription: "Expected to decode Int but found a string/data instead.", underlyingError: nil)
Then the value for Score is String, change the type in the declaration line: let score : String and you have to change the sort closure. I updated the answer.
1

If array contains dictionary then you can use this code for sorting:

let sortedArray = json.sort { $0["Score"] as! Int < $1["Score"] as! Int }
print(sortedArray)

and if you are using bean class then you can use dot(.) properties for sorting:

let sortedArray = json.sort { $0.Score < $1.Score }
print(sortedArray)

4 Comments

I don't see in the question where OP is using SwiftyJSON... I think they're not using it...
@Moritz, i have updated my answer please check it again.
.intValue is a SwiftyJSON getter. I don't think OP uses SwiftyJSON.
The second error still occurs if the array is declared as NSArray. That's the main problem.
0

After parsing your json, you can sort your score array like this

var scoreArray = ["500", "0", "2000", "300", "900"]
array.sort { $0.compare($1, options: .numeric) == .orderedAscending }

1 Comment

I have json array and I'm using - let obj = NSSortDescriptor.init(key: key, ascending: false) but it is not sorting correctly. I want to sort according to ID. Array - { EastLong = "-75.54663212158209"; NorthLat = "40.07097483544585"; ServiceAreaBroughtBy = "Traffic Products"; ServiceAreaEnabled = 1; ServiceAreaID = 1024; ServiceAreaName = "Demo Traffic Products Office"; SouthLat = "40.0198272706342"; WestLong = "-75.63005399999997"; },
0

I did something like this before

First I created two arrays of dictionary

var jsonArray =  [(name:String, score:String)]()
var sortedscoreArray:[(name: String, score: String)] = []

and in getting json data you can create for loop

for I in 0..< jsonData.count{
  Let jsonInfo = jsonData[i]
  jsonArray.append((name: jsonInfo[“Name”].string!, score: jsonInfo[“Score"].string!))
}

and after you fill the json array pass it to sortedArray

sortedscoreArray =  jsonArray.sorted(by: { $0.score < $1.score })

Comments

0
 let sortedResults =  self.json?.sorted(by: {$0.name ?? EMPTY_STRING < $1.name ?? EMPTY_STRING }) ?? []

1 Comment

A code-only answer is not high quality. While this code may be useful, you can improve it by saying why it works, how it works, when it should be used, and what its limitations are. Please edit your answer to include explanation and link to relevant documentation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.