Reputation: 1204
I have an array of object User(val name: String, val role: String)
. Role can be: leader, student, teacher, parent. And should be sorted in that order. I've read some article about Comparator but haven't figure out how they work. Can you please add some explanation too?
Upvotes: 11
Views: 17018
Reputation: 431
Let your array be
val listOfUser = listOf<User>(
User("Ben", "Teacher"),
User("Bheem", "Student"),
User("Steve", "Student"),
User("Fora", "Student"),
User("Jacker", "Operator")
)
To sort this array you can use sortedWith method and a comparator of your object whose return type is also list is as shown below
val sortedUsersList = listOfUser.sortedWith(compareBy { it.role })
If you use sortBy or sortByDescending methods their return will be Unit but not list.
Upvotes: 3
Reputation: 4253
its so simple if you use kotlin, you can use sort
method. for example
you have list like
val listOfUser = listOf<User>(
User("raka", "teacher"),
User("adi", "student"),
User("steve", "student"),
User("mark", "student"),
User("jack", "operator")
)
if you want to sort, you just access your variable and use sort
method. like this
listOfUser.sortedBy {it.role} // if you want to sort ASCENDING by roles
listOfUser.sortedByDescending { it.role } // if you want to sort DESC by roles
Upvotes: 5
Reputation: 822
I believe the simplest way to solve your problem is to use enum classes, since they already implement the Comparable interface. You can't use String directly since it would use the String compareTo
method, which sorts them alphabetically.
Essentially you would have to do something like this:
enum class Role { LEADER, STUDENT, TEACHER, PARENT }
data class User(val name: String, val role: Role)
fun main(args: Array<String>) {
val trumpino = User("trumpino", Role.STUDENT)
val obamino = User("barack-obamino", Role.PARENT)
val bushino = User("george-bushino", Role.TEACHER)
val kennedino = User("kennedino", Role.LEADER)
val mlist = listOf<User>(trumpino, obamino, bushino, kennedino)
val result = mlist.sortedBy { it.role }
println(result)
}
But that would require you to change other pieces of your code if you're already using strings. You could possibly add an extension method to parse the string into an enum or use the valueOf
method which is explained in this other answer.
The comparator interface is meant to be used with the functional constructs from the kotlin library, in constrast with the comparable interface which is meant to represent the inherent ordering from your class (if it has one). If you need to order your data in a way that's different from its normal ordering (which would be defined by the comparable interface), you use comparator with some ordering method like sortedWith.
With comparator you could do something like, which specify a complex ordering in a simple manner:
mlist.sortedWith(compareByDescending { it.role }.thenBy { it.name })
In contrast to the comparable interface:
class User(val name: String, val role: Role) : Comparable {
override operator fun compareTo(other: User) : Int {
return when {
other.role > this.role -> 1
other.role < this.role -> -1
other.name > this.name -> 1
other.name < this.name -> -1
else -> 0
}
}
}
They both act in the same way in the sense that the value they return is meant to represent the ordering of between this
and other
, as explained by the kotlin documentation of compareTo:
Compares this object with the specified object for order. Returns zero if this object is equal to the specified other object, a negative number if it's less than other, or a positive number if it's greater than other.
But since comparator is a functional construct, it has a diferent interface from its OOP counterpart as it's meant to be used with lambda expressions.
abstract fun compare(a: T, b: T): Int
But it acts in the same way, as explained in the java documentation for Comparator
Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
Upvotes: 4
Reputation: 2283
You can instantiate a HashMap for indicating roles priority:
private val roles: HashMap<String, Int> = hashMapOf(
"Leader" to 0,
"Student" to 1,
"Teacher" to 2,
"Parent" to 3
)
fun sortUsers(users: ArrayList<User>): ArrayList<User> {
val comparator = Comparator { o1: User, o2: User ->
return@Comparator roles[o1.role]!! - roles[o2.role]!!
}
val copy = arrayListOf<User>().apply { addAll(users) }
copy.sortWith(comparator)
return copy
}
In the comparator, if the result of the subtraction is negative, it will sort it in the order [o1, o2]. Otherwise, [o2, o1]. So in this case, it will sort your list in an ascending manner (since we have the highest priority as 0 - Leader as indicated in the HashMap).
For example, if we have o1
as Teacher
and o2
as Leader
,
the result of the comparator will be: 2 - 0 = 2
which is a positive integer. Hence, it is sorted as [o2 (Leader), o1 (Teacher)]
.
Reversing the roles however yields the opposite result: 0 - 2 = -2
and hence it will be ordered [o1 (Teacher), o2 (Leader)]
.
You can verify this result with:
fun main(args: Array<String>) {
val users = arrayListOf(
User("john", "Student"),
User("tim", "Teacher"),
User("nice", "Student"),
User("hey", "Leader"),
User("you", "Parent")
)
println(sortUsers(users))
}
Which prints out: [User(name=hey, role=Leader), User(name=john, role=Student), User(name=nice, role=Student), User(name=tim, role=Teacher), User(name=you, role=Parent)]
Upvotes: 13