I've got Workout
class with Difficulty
property
enum Difficulty: String {
case easy = "easy"
case moderate = "moderate"
case hard = "hard"
}
class Workout {
var name: String?
var difficulty: Difficulty?
.
.
.
}
I'd like to sort an array of workouts by the difficulty property. I know I can achieve that by assigning enum's raw value to Int value and compare these values as follows:
data.sort { $0.workout.difficulty!.rawValue < $1.workout.difficulty!.rawValue }
But I really want this enum to store string, since it's convenient to assign it to label text down the line without ugly switch-case hacks, and be comparable in some way.
How to achieve that?
ENUM values are sorted based on their index numbers, which depend on the order in which the enumeration members were listed in the column specification.
In the main() method, we've created an array list of custom objects list, initialized with 5 objects. For sorting the list with the given property, we use the list's sort() method. The sort() method takes the list to be sorted (final sorted list is also the same) and a comparator.
These values are public static final , ie (Constant objects of that specific Enum Type), and its Order is very Important for mapping the variables to these Objects. values() is a static method of Enum , which always returns the values in same order.
sort() method to sort a list of objects using some examples. By default, the sort() method sorts a given list into ascending order (or natural order). We can use Collections. reverseOrder() method, which returns a Comparator, for reverse sorting.
Implement the Comparable
protocol on your enum
. It gives you a static func < (lhs: Difficulty, rhs: Difficulty) -> Bool
method where you define the sort.
Here is a full sample using a property to simplify the ordering
enum Difficulty: String, Comparable {
case easy = "easy"
case moderate = "moderate"
case hard(String) = "hard"
private var sortOrder: Int {
switch self {
case .easy:
return 0
case .moderate:
return 1
case .hard(_):
return 2
}
}
static func ==(lhs: Difficulty, rhs: Difficulty) -> Bool {
return lhs.sortOrder == rhs.sortOrder
}
static func <(lhs: Difficulty, rhs: Difficulty) -> Bool {
return lhs.sortOrder < rhs.sortOrder
}
}
Making it possible to use
data.sort { $0.workout.difficulty! < $1.workout.difficulty! }
edit/update: Swift 5.1 or later
You can change your enumeration RawValue type to integer and use its rawValue to sort your Workouts. Btw you should use a structure instead of a class and similar to what was suggested by Igor you could make your struct comparable instead of the enumeration:
struct Workout {
let name: String
let difficulty: Difficulty
}
extension Workout {
enum Difficulty: Int { case easy, moderate, hard }
}
extension Workout: Comparable {
static func <(lhs: Workout, rhs: Workout) -> Bool { lhs.difficulty.rawValue < rhs.difficulty.rawValue }
}
let wk1 = Workout(name: "night", difficulty: .hard)
let wk2 = Workout(name: "morning", difficulty: .easy)
let wk3 = Workout(name: "afternoon", difficulty: .moderate)
let workouts = [wk1, wk2, wk3] // [{name "night", hard}, {name "morning", easy}, {name "afternoon", moderate}]
let sorted = workouts.sorted() // [{name "morning", easy}, {name "afternoon", moderate}, {name "night", hard}]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With