Kotlin 如何根据多种类型和值进行排序?
How to sort based on multiple types and values in Kotlin?
给出以下 类:
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
如果我们创建一个列表:
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))
并排序:
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 }))
然后我得到一个列表,如果它是通过以下注释代码创建的:
// 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"))
这样排序有没有更好的方法?
我读
已经存在,但无法将其应用到我的代码中。
是的,它可以在一次操作中实现(但相当复杂)并且您的想法是正确的,compareBy
可以为您解决问题
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
}
}))
我们在这里做什么:
- 我们正在为 Item 的实现创建合成比较器。当然,如果这是常见的用例,这个数字可能只是界面中的另一个字段。
- 我们正在定义要在
Server
和 Local
上进行比较的字段,因为它们具有额外的排序标准。
- 我们将在步骤 1 和 2 中创建的比较器传递给
compareBy
函数。
此操作后 items
集合排序:
[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:如果 Item
的名字也应该被排序——你可以很容易地在适当的地方再添加一个比较器,比如 Item::name
。
给出以下 类:
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
如果我们创建一个列表:
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))
并排序:
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 }))
然后我得到一个列表,如果它是通过以下注释代码创建的:
// 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"))
这样排序有没有更好的方法?
我读
是的,它可以在一次操作中实现(但相当复杂)并且您的想法是正确的,compareBy
可以为您解决问题
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
}
}))
我们在这里做什么:
- 我们正在为 Item 的实现创建合成比较器。当然,如果这是常见的用例,这个数字可能只是界面中的另一个字段。
- 我们正在定义要在
Server
和Local
上进行比较的字段,因为它们具有额外的排序标准。 - 我们将在步骤 1 和 2 中创建的比较器传递给
compareBy
函数。
此操作后 items
集合排序:
[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:如果 Item
的名字也应该被排序——你可以很容易地在适当的地方再添加一个比较器,比如 Item::name
。