'Order an array of objects by the value of their enums in swift

I have an array of CLBeacon objects which all have a property .proximity.

I want to order the array by this property which contains the CLProximity enum. So I want all objects to be in order IMMEDIATE, NEAR, FAR, UNKNOWN.

Is there a way to do this neatly without resorting to a bunch of if statements?



Solution 1:[1]

If you define a (computed read-only) property sortIndex of CLProximity

extension CLProximity {
    var sortIndex : Int {
        switch self {
        case .Immediate:
            return 0
        case .Near:
            return 1
        case .Far:
            return 2
        case .Unknown:
            return 3
        }
    }
}

then you can sort an array of beacons with

let sortedBeacons = sorted(beacons) { $0.proximity.sortIndex < $1.proximity.sortIndex }

If .Unknown is the only CLProximity value that needs "special treatment" and all other possible values are in the desired relative order then you can simplify the property definition to

extension CLProximity {
    var sortIndex : Int {
        return self == .Unknown ? Int.max : rawValue
    }
}

Solution 2:[2]

You can use custom comparator and sort an array using that ,

You will "say" for all objects that has "unknown" proximity are "bigger" than others

var sortedArray = persons.sortedArrayUsingComparator {
    (obj1, obj2) -> NSComparisonResult in


    if obj1.proximity.rawValue == obj12.proximity.rawValue {
        return NSComparisonResult.OrderedSame
    } else if obj1.proximity == .UNKNOWN || obj1.proximity.rawValue > obj12.proximity.rawValue {
        return NSComparisonResult.OrderedDescending
    }
    return NSComparisonResult.OrderedAscending
}

Solution 3:[3]

Based on what Julia wrote above I had cobbled this together:

    self.beacons = beacons as! [CLBeacon]

    var tempBeacons = zip(self.beacons, self.beacons.map({
        (b: CLBeacon) -> Int in
        if b.proximity == .Immediate {
            return 0
        } else if b.proximity == .Near {
            return 1
        } else if b.proximity == .Far {
            return 2
        } else if b.proximity == .Unknown {
            return 3
        }
        return 0
    }))

    self.beacons = sorted(tempBeacons, {$0.1 < $1.1}).map({ $0.0 })

Thanks all!

Solution 4:[4]

Based on @Martin answer. You can also create Int enum and assign value to it and then sort it like below.

enum myEnum: Int {
    case A = 0
    case B = 1
    case C = 2
    case D = 3
}
let myData : [myEnum:[String]] = [.C:["3"],.D:["4"],.B:["2"],.A:["1"]]
print(myData.first?.key)

let newData = myData.sorted(by: { $0.key.rawValue < $1.key.rawValue })
print(newData.first?.key)

Hope this helps

Solution 5:[5]

Swift 5

Now you can just add Comparable to your enum and it respects the order

enum ContainerLevel: Comparable {
case empty
case almostEmpty
case halfFull
case almostFull
case full    

}

//Are we running low?

let needMoreCoffee = coffeeMugLevel > .halfFull

print(needMoreCoffee) //true

Link to more Code examples

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 ogres
Solution 3 Alper
Solution 4 Abdul Rehman
Solution 5 devjme