Singhak
Singhak

Reputation: 8896

Sorting Custom Object Array in swift with different parameter

I have an array of a custom class

class GameInfo {
var gameStatus :String
var country : String
var isSelected : Bool
}

Here, gameStatus may be "*"/"1-0"/"1/2-1/2"

I want to sort the array first by isSelected, then gameStatus, then country.

I tried sortInPlace but didn't work for me.

suppose this is my array

let list = [
    GameInfo(gameStatus: "*", country: "Italy", isSelected: true),
    GameInfo(gameStatus: "1/2-1/2", country: "France", isSelected: true),
    GameInfo(gameStatus: "1-0", country: "Italy", isSelected: false),
    GameInfo(gameStatus: "*", country: "Germany", isSelected: false),
    GameInfo(gameStatus: "0-1", country: "Italy", isSelected: true),
 GameInfo(gameStatus: "1/2-1/2", country: "France", isSelected: false),
    GameInfo(gameStatus: "*", country: "UK", isSelected: false)
]

Selected games should be on top if with in selected game there is any live game that game should be on top even with in any game related to my country that game on top

suppose my country is Italy then sorted order of array is

     GameInfo(gameStatus: "*", country: "Italy", isSelected: true),
    GameInfo(gameStatus: "0-1", country: "Italy", isSelected: true),
    GameInfo(gameStatus: "1/2-1/2", country: "France", isSelected: true),
     GameInfo(gameStatus: "*", country: "Germany", isSelected: false),
    GameInfo(gameStatus: "*", country: "UK", isSelected: false)
    GameInfo(gameStatus: "1-0", country: "Italy", isSelected: false),
   GameInfo(gameStatus: "1/2-1/2", country: "France", isSelected: false),

Upvotes: 0

Views: 650

Answers (3)

Wolverine
Wolverine

Reputation: 4329

Try this.

your class look like below

import UIKit

class GameInfo : NSObject {

    var gameStatus :String = ""
    var country : String = ""
    var isSelected : Bool = false

    init(gameStatus: String, country: String, isSelected: Bool) {
        self.gameStatus = gameStatus
        self.country = country
        self.isSelected = isSelected
    }
}

And use this code for sorting. As per your need, you can set ascending parameter.

let list :NSArray = [
    GameInfo(gameStatus: "*", country: "Italy", isSelected: true),
    GameInfo(gameStatus: "1/2/21", country: "France", isSelected: true),
    GameInfo(gameStatus: "1-0", country: "UK", isSelected: true),
    GameInfo(gameStatus: "*", country: "Germany", isSelected: false),
    GameInfo(gameStatus: "0-1", country: "Italy", isSelected: true),
    GameInfo(gameStatus: "1/2-1/2", country: "UK", isSelected: false)
]

let isSelectedDescriptor: NSSortDescriptor = NSSortDescriptor(key: "isSelected", ascending: false)
let gameStatusDescriptor: NSSortDescriptor = NSSortDescriptor(key: "gameStatus", ascending: true)
let countryDescriptor: NSSortDescriptor = NSSortDescriptor(key: "country", ascending: true)


let sortedResults: NSArray = list.sortedArrayUsingDescriptors([isSelectedDescriptor,gameStatusDescriptor,countryDescriptor])

dump(sortedResults)

Upvotes: -1

Duyen-Hoa
Duyen-Hoa

Reputation: 15784

try this (old style Objective-C array sorting):

let sortedArray = (yourArray as NSArray).sortedArrayUsingDescriptors([
  NSSortDescriptor(key: "isSelected", ascending: true),
  NSSortDescriptor(key: "gameStatus", ascending: true),
  NSSortDescriptor(key: "country", ascending: true)
]) as! [GameInfo]

In that case, your GameInfo class must be like this. It's not the easy way to resolve your problem, just for info. Sorting with multiple conditions is very easy and natural with NSSortDescriptors but for Objective-C only, unless our swift classes are under some conditions (implementations).

class GameInfo : NSObject {
    var gameStatus: String?
    var country: String?
    var isSelected: Bool

    init(gameStatus: String, country: String, isSelected: Bool) {
        self.gameStatus = gameStatus
        self.country = country
        self.isSelected = isSelected
    }

    override func valueForKey(key: String) -> AnyObject? {
        if (key == "gameStatus") {
            return self.gameStatus
        } else if (key == "country") {
            return self.country
        } else if (key == "isSelected") {
            return self.isSelected
        } else {
            return nil
        }
    }
}

Upvotes: 1

Luca Angeletti
Luca Angeletti

Reputation: 59496

Solution 1

You can write your own logic into the closure you pass to sort.

So given this class

class GameInfo {
    var gameStatus: String
    var country: String
    var isSelected: Bool

    init(gameStatus: String, country: String, isSelected: Bool) {
        self.gameStatus = gameStatus
        self.country = country
        self.isSelected = isSelected
    }
}

and this list

let list = [
    GameInfo(gameStatus: "A", country: "Italy", isSelected: true),
    GameInfo(gameStatus: "A", country: "France", isSelected: true),
    GameInfo(gameStatus: "B", country: "UK", isSelected: true),
    GameInfo(gameStatus: "B", country: "Germany", isSelected: false),
    GameInfo(gameStatus: "A", country: "Italy", isSelected: true),
    GameInfo(gameStatus: "B", country: "UK", isSelected: false)
]

you can created a sorted list this way

let sorted = list.sort {
    guard $0.isSelected == $1.isSelected else { return $0.isSelected }
    guard $0.gameStatus == $1.gameStatus else { return $0.gameStatus < $1.gameStatus }
    guard $0.country == $1.country else { return $0.country < $1.country }
    return true
}

Solution 2

You can make your GameInfo class conform to Comparable.

class GameInfo: Comparable {
    var gameStatus: String
    var country: String
    var isSelected: Bool

    init(gameStatus: String, country: String, isSelected: Bool) {
        self.gameStatus = gameStatus
        self.country = country
        self.isSelected = isSelected
    }
}

func ==(left: GameInfo, right: GameInfo) -> Bool {
    return
        left.isSelected == right.isSelected &&
        left.gameStatus == right.gameStatus &&
        left.country == right.country
}

func <(left: GameInfo, right: GameInfo) -> Bool {
    guard left.isSelected == right.isSelected else { return left.isSelected }
    guard left.gameStatus == right.gameStatus else { return left.gameStatus < right.gameStatus }
    guard left.country == right.country else { return left.country < right.country }
    return true
}

Now you can just invoke sort without the need of furthers params.

let sorted = list.sort()

Upvotes: 1

Related Questions