Given following classes:
interface Item {
val name: String
}
data class Server(override val name: String, val id: String) : Item
data class Local(override val name: String, val date: Int) : Item
data class Footer(override val name: String) : Item
If we create a list:
val items = arrayListOf<Item>()
items.add(Server("server", "b"))
items.add(Local("local", 2))
items.add(Footer("footer"))
items.add(Server("server", "a"))
items.add(Local("local", 1))
items.add(Footer("footer"))
items.add(Server("server", "c"))
items.add(Local("local", 0))
And sort it:
val groupBy = items.groupBy { it.name }
val partialSort = arrayListOf<Item>()
//individually sort each type
partialSort.addAll(groupBy["local"]!!.map { it as Local }.sortedWith(compareBy({ it.date })))
partialSort.addAll(groupBy["server"]!!.map { it as Server }.sortedWith(compareBy({ it.id })))
partialSort.addAll(groupBy["footer"]!!.map { it as Footer })
//this can be avoided if above three lines are rearranged
val fullSort = partialSort.sortedWith(compareBy({ it is Footer }, { it is Local }, { it is Server }))
Then I get a list which looks like if it was created by following commented code:
// items.add(Server("server", "a"))
// items.add(Server("server", "b"))
// items.add(Server("server", "c"))
// items.add(Local("local", 0))
// items.add(Local("local", 1))
// items.add(Local("local", 2))
// items.add(Footer("footer"))
// items.add(Footer("footer"))
Is there a better way to sort it this way? I read How to sort based on/compare multiple values in Kotlin? and Sort collection by multiple fields in Kotlin already but couldn't apply that to my code.
Yes, it can be achieved in single operation (but pretty complex one) and you're thinking in right way, compareBy
can do the trick for you
items.sortWith(compareBy({
when (it) {
is Server -> -1
is Local -> 0
is Footer -> 1
else -> Integer.MAX_VALUE
}
}, {
when (it) {
is Server -> it.id
is Local -> it.date
else -> 0
}
}))
What we do here:
Server
and Local
because they have additional criterion of sorting. compareBy
function.After this operation items
collections is sorted:
[Server(name=server, id=a), Server(name=server, id=b), Server(name=server, id=c), Local(name=local, date=0), Local(name=local, date=1), Local(name=local, date=2), Footer(name=footer), Footer(name=footer)]
UPD: If name of Item
shoud be subject of sorting too — you can easily add one more comparator like Item::name
in appropriate place.