Class 使用特定于子类型的行为对混合列表进行排序Kotlin
我有一个项目列表,这些项目共享一个基类,但是非常不同,我想先按它们的类对它们进行排序,然后按特定于该类的比较器对它们进行排序 例如Class 使用特定于子类型的行为对混合列表进行排序Kotlin,class,sorting,kotlin,comparator,Class,Sorting,Kotlin,Comparator,我有一个项目列表,这些项目共享一个基类,但是非常不同,我想先按它们的类对它们进行排序,然后按特定于该类的比较器对它们进行排序 例如subtya应该按照特定于该类的属性foo进行排序,而subtyb应该按照特定于该类的属性bar1然后是bar2进行排序,我需要对包含这两个属性的列表进行排序 排序的实际顺序并不重要,只是它在运行时内是一致的,因此可以通过首先对这些对象的两个列表进行排序来检查它们是否相等 (到目前为止,我刚刚使用了一个lazy属性,它将对象添加到一个集合中并检查其索引,从而为相等的对
subtya
应该按照特定于该类的属性foo
进行排序,而subtyb
应该按照特定于该类的属性bar1
然后是bar2
进行排序,我需要对包含这两个属性的列表进行排序
排序的实际顺序并不重要,只是它在运行时内是一致的,因此可以通过首先对这些对象的两个列表进行排序来检查它们是否相等
(到目前为止,我刚刚使用了一个lazy属性,它将对象添加到一个集合中并检查其索引,从而为相等的对象提供相同的sortkey,但是这个缓存正在增长到可笑的大小,这使得速度非常慢)
如何按类对这些对象进行分组,然后使用特定于类的比较器?下面是一些可以满足您需要的东西 我们为所有子类型提供单独的比较器,并简单地按类型分组,使用自己的比较器对每个组进行排序,然后简单地按类名对组进行排序,并以连续的方式展平每个组中的元素 下面是演示它的代码示例
- 添加了实用程序功能
,以执行此排序sortedUsing
- 添加了一个实用程序类型
,只是为了更方便地传递类型安全类+ComparatorTypeComparator
所以,当你对亚型A和亚型B的类型进行排序时,它们是使用foo还是bar1和bar2,或者其他什么来排序的?@mattfanke我不确定我是否理解你的问题。你是在问课程的顺序吗?如果这是个问题,那真的没关系,我正在考虑使用类的hashcode或其他东西。编辑:要清楚,如果解决方案需要以其他方式订购,那就太好了。谢谢。但是,有两个问题:这是针对一个多平台项目的,因此这项工作是否会将
:class.java
替换为::class
和class
替换为KClass
?其次,尝试访问comparator对象的类的方法而不是将它们作为参数是否明智?另外,如果您想处理具有可空元素的列表,您可以添加另一个扩展,如sofun List.sortedNullableUsing(vararg typeComparators:TypeComparator):List=(0直到计数{it==null})。map{null}+filterNotNull().sortedUsing(*typeComparators)
fun <T : Any> List<T>.sortedUsing(
vararg typeComparators: TypeComparator<out T>
): List<T> {
@Suppress("UNCHECKED_CAST")
fun <R : T> TypeComparator<R>.sort(list: List<T>): List<R> = (list as List<R>).sortedWith(comparator)
val comparators = typeComparators.associateBy { it.type }
return groupBy { it::class }
.mapValues { (klass, list) ->
val typeComparator = comparators[klass]
?: typeComparators.firstOrNull { klass.isSubclassOf(it.type) }
?: list.firstOrNull()?.tryMakeComparator()
?: throw IllegalArgumentException("Missing comparator for type: $klass")
typeComparator.sort(list)
}
.map { it }
.sortedBy { it.key.qualifiedName }
.flatMap { it.value }
}
@Suppress("UNCHECKED_CAST")
private fun <T : Any> T.tryMakeComparator(): TypeComparator<T>? {
if (this !is Comparable<*>) {
return null
}
return TypeComparator(this::class as KClass<T>, Comparator { o1, o2 ->
val c1 = o1 as Comparable<Comparable<T>>
val c2 = o2 as Comparable<T>
c1.compareTo(c2)
})
}
data class TypeComparator<T : Any>(
val type: KClass<T>,
val comparator: Comparator<T>
)
open class Base
data class SubtypeA(
val foo: Int
) : Base()
data class SubtypeB(
val bar1: String,
val bar2: String
) : Base()
fun main() {
val list = listOf(
SubtypeA(5),
SubtypeB("foo", "x"),
SubtypeA(42),
SubtypeA(2),
SubtypeB("bar", "y"),
SubtypeB("bar", "x")
)
val sorted = list.sortedUsing(
TypeComparator(SubtypeA::class, Comparator.comparing { a: SubtypeA -> a.foo }),
TypeComparator(SubtypeB::class, Comparator.comparing { b: SubtypeB -> b.bar1 }.thenComparing { b: SubtypeB -> b.bar2 })
)
sorted.forEach { println(it) }
// prints:
// SubtypeA(foo=2)
// SubtypeA(foo=5)
// SubtypeA(foo=42)
// SubtypeB(bar1=bar, bar2=x)
// SubtypeB(bar1=bar, bar2=y)
// SubtypeB(bar1=foo, bar2=x)
}