How to Sort Objects by Its Enum Value

How to sort objects by its enum value?

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}]

How to sort a list of objects by contained enum?

First approach

Reorder the enum entries so the resulting order follows your requirements:

enum Model {
SEDAN, BMW, UNICORN
}

then you can sort your list as follows:

l.sort(Comparator.comparing(Car::getModel));

Note that enum values are compared by their order in code (i.e. ordinal())


Second approach

Assign a value to each enum entry:

enum Model {
SEDAN(0), BMW(1), UNICORN(2);
final int val;
Model(int val) { this.val = val; }
}

then you can sort your list as follows:

l.sort(Comparator.comparing((Car car) -> car.getModel().val));


How to sort a list of objects by an enum field?

name returns the name of the enum constants, so you can use that in Comparator.comparing:

items.sort(Comparator.comparing(item -> item.level.name()));

After thinking about a bit further, I don't actually think this might not be a good design. If you do this, then you can't freely change your enum constant names, because that might also change the sort order. This is especially problematic if someone else who doesn't know that you are relying on enum names, reads your code and renames the constants for whatever reason (renaming normally won't break things if you use the IDE's rename tool), then your sorting code would sort them in a different order, which could potentially break many other things.

sort list of custom objects based on enum in kotlin

Use sortedBy function. It will do the job very easily.

val ans = list.sortedBy { it.severity }

iOS Swift - Sort array by enum pattern

Here is one way to approach it. First use map to associate a sorting Int index with each item. Use a dictionary to keep track of the last index associated with each Kind and increment it by the number of different kinds. This will give a unique sorting index to every item in your array with items being sorted into the desired patten due to the increments added to repeated Kinds.

enum Kind: Int, CaseIterable {
case movie, tv, trailer, genre, article
}

struct Item: CustomStringConvertible {
var description: String { "\(name): \(kind)" }

let id: Int
let name: String
let kind: Kind
}

let items: [Item] = [
.init(id: 1, name: "D", kind: .tv),
.init(id: 2, name: "B", kind: .movie),
.init(id: 3, name: "F", kind: .trailer),
.init(id: 4, name: "H", kind: .genre),
.init(id: 5, name: "J", kind: .article),
.init(id: 6, name: "C", kind: .tv),
.init(id: 7, name: "A", kind: .movie),
.init(id: 8, name: "E", kind: .trailer),
.init(id: 9, name: "G", kind: .genre),
.init(id: 10, name: "I", kind: .article)]

// Dictionary used to generate a unique sorting index for each kind
var dict: [Kind: Int] = [:]

typealias IndexedItem = (index: Int, element: Item)

// Assign a sorting index to each item. Repeated Kinds will be incremented by
// allCases.count so that they sort into the next group
let items2: [IndexedItem] = items.map { item in
dict[item.kind, default: item.kind.rawValue] += Kind.allCases.count
return (dict[item.kind]!, item)
}

let result = items2.sorted { $0.index < $1.index }.map(\.element)
print(result)

Output

[B: movie, D: tv, F: trailer, H: genre, J: article, A: movie, C: tv, E: trailer, G: genre, I: article]


Radix Sort - A faster sort

Since all of the indices are unique, we can create the result array with a radix sort:

// Assign a sorting index to each item.  Repeated Kinds will be incremented by
// allCases.count so that they sort into the next group
let cases = Kind.allCases.count
let items2: [IndexedItem] = items.map { item in
dict[item.kind, default: item.kind.rawValue - cases] += cases
return (dict[item.kind]!, item)
}

// Use a radix sort to order the items
let maxIndex = dict.values.max() ?? -1
var slots = [Item?](repeating: nil, count: maxIndex + 1)
items2.forEach { slots[$0.index] = $0.element }
let result = slots.compactMap { $0 }

This amounts to creating an array of nil large enough to hold the largest index, putting the items into the array using their index, and then removing the nils (empty slots) with compactMap(). This sorting algorithm is O(n) instead of O(n log n) like the general sorting algorithm.

Swift sort an array of enums by their enum declared order

Add a comparable protocol to the enum?

enum EducationOptions: String {
case gcse = "GCSE"
case aLevel = "A Level"
case bachelors = "Bachelors"
case masters = "Masters"
case doctorate = "Doctorate"
case other = "Other"

var order: Int {
switch self {
case .gcse: return 1
case .aLevel: return 2
case .bachelors: return 3
case .masters: return 4
case .doctorate: return 5
case .other: return 6
}
}

extention EquctionOptions: Comparable {

static func < (lhs: EducationOptions, rhs: EducationOptions) -> Bool {
lhs.order < rhs.order
}
}

then you can just sort the array.

let array = [.masters, .gcse, .aLevel]
let sorted = array.sorted(by: { $0 < $1 })

there may be a better way to set the order values in the array while having the String raw value as well, but not of the top of my head

How to sort array by enum value

You can use IEnumerable.OrderBy.

If you sort by an enum-value it will look at the underlying type (usually int) and sort by that. This means the best solution would just be like this:

arr.OrderBy(c => c.TheEnumProperty);

This method will return a sorted IEnumerable which you can cast back to an array with IEnumerable.ToArray.

Sort array by enum order and not value

    const order = [];
for (let key in MyEnum) {
order.push(key);
}
const newArray = myArray.sort((a, b) => {
const index1 = order.findIndex(key => MyEnum[key] === a.code);
const index2 = order.findIndex(key => MyEnum[key] === b.code);
return index1 - index2;
});

This will sort your array, in the order keys are stored in MyEnum.

How to sort a set of objects according to Enum field in java

Assuming you have the values in a list called yourList. Of course you can add to the set directly, if that fits your needs better.

SortedSet<User> set = new TreeSet<User>(Comparator.comparing(User::userRole)
.thenComparing(User::userName));
set.addAll(yourList)


Related Topics



Leave a reply



Submit