我有狗课程和cat 课程.我想一遍又一遍地创建一个列表,其中有2只狗,然后有1只cat ,直到我们的狗用完.列表应该按照狗的顺序对狗进行排序.在Kotlin中最有效的方法是什么?

以下是我当前正在工作的代码:

enum class CatBreed { MAINE_COON, BALINESE, BENGAL }
enum class DogBreed { ITALIAN_GREYHOUND, BEAGLE, AKITA, POMERANIAN, SHIH_TZU, DACHSHUND }
data class Dog(val breed: DogBreed, val order: Int)
data class Cat(val breed: CatBreed)
abstract class PetsItem
data class DogItem(val dog: Dog) : PetsItem()
data class CatItem(val cat: Cat) : PetsItem()

var petsList = arrayListOf<PetsItem>()
val dogs = arrayListOf(Dog(ITALIAN_GREYHOUND, 3), Dog(BEAGLE, 2), Dog(AKITA, 1), Dog(POMERANIAN, 6), Dog(SHIH_TZU, 5), Dog(DACHSHUND, 4))
val cats = arrayListOf(Cat(MAINE_COON), Cat(BALINESE), Cat(BENGAL))

val orderedDogs = ArrayList(dogs.asSequence()
    .sortedBy { it.order }
    .toList())

for ((index, dog) in orderedDogs.withIndex()) {
    petsList.add(DogItem(dog = dog))
    if (index % 2 == 1) {
        if (cats.isNotEmpty()) {
            petsList.add(CatItem(cat = cats.removeAt(0)))
        }
    }
}

我有这个代码:

val list = ArrayList(dogs.asSequence()
    .sortBy { it.order }
    .map { DogItem(dog = it) }
    .toList())

这在将Dog对象转换为DogProject对象方面似乎非常有效.但我不知道如何修改它以允许cat .

那么,有人知道是否有比我目前正在做的更有效的方法来根据我想要的创建列表吗?

推荐答案

我认为对于如此小的列表来说,这已经足够有效了:

val petsList: List<PetsItem> = dogs
    .sortedBy(Dog::order)
    .map(::DogItem)
    .zip2To1(cats.map(::CatItem))

尽管仅使用内置函数可能可以将狗列表与cat 列表压缩,但尊重所有边缘情况将相当困难,并且可能效率低下.这就是为什么我使用了定制功能:

fun <T> Iterable<T>.zip2To1(other: Iterable<T>): List<T> {
    val iteratorThis = iterator()
    val iteratorOther = other.iterator()
    if (!iteratorThis.hasNext()) return emptyList()
    if (!iteratorOther.hasNext()) return if (this is List) this else this.toList()
    val result = mutableListOf<T>()

    result.add(iteratorThis.next())
    while (iteratorThis.hasNext()) {
        result.add(iteratorThis.next())
        result.add(iteratorOther.next())
        if (!iteratorOther.hasNext()) iteratorThis.forEachRemaining { result.add(it) }
        if (iteratorThis.hasNext()) result.add(iteratorThis.next())
    }

    return result
}

这将比for循环更有效,因为它不需要从可变cats列表中删除元素,只是将两个列表一起迭代.它的另一个好处是,您的列表可以是不可变的,并且可以轻松地与其他列表转换链接在一起.

此解决方案仅使用列表操作,与示例中使用的序列相反.当您有很多元素和长的转换链时,序列是很棒的,因为元素不会复制到新列表并在每次转换时再次迭代,而是在一次迭代中完成.不过,设置它们确实会产生额外的成本,因为它们是基于协程的,并且在序列产生新值(然后挂起)时需要来回切换.在没有实际对其进行基准测试的情况下,我仍然认为对于这个特定的情况,列表会更适合.

也就是说,您可以轻松地将所有内容切换为序列:

val dogs = sequenceOf(...)
val cats = sequenceOf(...)

就是这样.petsList不需要touch ,因为标准lib为序列提供了(大部分)与为列表提供的相同的转换函数.如果您希望最终将结果序列转换为列表,则只需添加.toList()即可.您现在唯一缺少的是序列的自定义zip2To1函数.好吧,就是这样:

fun <T> Sequence<T>.zip2To1(other: Sequence<T>): Sequence<T> {
    val iteratorThis = iterator()
    val iteratorOther = other.iterator()
    if (!iteratorThis.hasNext()) return emptySequence()
    if (!iteratorOther.hasNext()) return this

    return sequence {
        yield(iteratorThis.next())
        while (iteratorThis.hasNext()) {
            yield(iteratorThis.next())
            yield(iteratorOther.next())
            if (!iteratorOther.hasNext()) yieldAll(iteratorThis)
            if (iteratorThis.hasNext()) yield(iteratorThis.next())
        }
    }
}

结束语:开发应用程序时,效率很少是最重要的目标.代码应该尽可能简洁和清晰,以便易于理解.这将防止错误并提高可维护性.

Kotlin相关问答推荐

测试Compose Multiplatform UI时,为另一个文件设置ComposeRule()

在Jetpack Compose中创建波浪式文本动画:顺序中断问题

用A*搜索算法解决特修斯和米诺陶尔难题

为什么使用 return instance ?: synchronized(this) { instance ?: PreferenceParameterState(context) } 时无法获得单例?

如何将消费者放入 Kotlin 的 map 中?

列表在 android WebView 中没有正确迭代

Gradle:无法创建 ExtensiblePolymorphicDomainObjectContainer

kotlin 父类具有依赖于抽象变量的变量

在 Kotlin 中,为什么在 `+` 之前但在 `.` 之前没有换行符?

Kotlin 插件错误:无法为类 org.jetbrains.kotlin.gradle.tasks.KotlinCompile 生成代理类

Kotlin-Java 互操作不能与可变参数一起使用

如何使用 Coil 从 URL 获取位图?

以编程方式重新启动 Spring Boot 应用程序/刷新 Spring 上下文

哪里可以找到aapt2日志(log)?

如何在kotlin语言中将字符转换为ascii值

Kotlin:如何修改成对的值?

Kotlin reflect proguard SmallSortedMap

未解决的参考 dagger 2 + kotlin + android gradle

在 Kotlin 函数上使用 Mokito anyObject() 时,指定为非 null 的参数为 null

为什么在 Kotlin 中return可以返回一个return?