You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中如何遍历列表时同时获取当前项与下一项?

问题描述

需要对服务器返回的电影列表进行过滤转换,同时在判断当前项的条件时,要结合下一项的属性做额外判断。

数据结构

服务器返回的原始数据类:

data class BollywoodMovie(
    val year: String? = null,
    val movieList: List<NewMovieItem>? = null
)

data class NewMovieItem(
    val name: String? = null,
    val type: String? = null,
    val isReleaseNow: Boolean? = null,
    val screenNumber: String? = null
)

需要转换为目标数据类:

data class FilterMovieItem(
    val name: String,
    val type: String,
    val isReleasedInThreader: Boolean
)

当前尝试代码

已实现基础过滤转换,但无法在判断当前项时获取下一项:

fun main() {
    val movieList = listOf(
        NewMovieItem("Kisi Ka Bhai Kisi Ki Jaan", "action", true, "Screen 1"),
        NewMovieItem("Pathaan", "action", true, ""),
        NewMovieItem("Tu Jhoothi Main Makkaar", "romance"),
        NewMovieItem("r", "", true, "Screen 3"),
        NewMovieItem("Dasara", "romance", false, "Screen 1"),
        NewMovieItem("Kuttey", "comedy", false, "Screen 2"),
        NewMovieItem("Selfiee", "comedy", true, "Screen 3"),
        NewMovieItem("Selfiee", "other", false, "Screen 1"),
    )
    val unfilteredList = BollywoodMovie("2023", movieList)
    val unFilteredMovieList = unfilteredList.movieList.orEmpty()
    val (filterList, otherMovieItem) = filterData(unFilteredMovieList)
    println(filterList)
    println(otherMovieItem)
}

private fun filterData(unFilteredMovieList: List<NewMovieItem>): Pair<List<FilterMovieItem>, MutableList<FilterMovieItem>> {
    val otherMovieItem = mutableListOf<FilterMovieItem>()
    val filterList = unFilteredMovieList
        .asSequence()
        .mapNotNull { currentItem ->
            // 希望在这里同时获取下一项来添加额外判断条件
            if (!currentItem.name.isNullOrEmpty() && !currentItem.type.isNullOrEmpty() && currentItem.isReleaseNow != null) {
                FilterMovieItem(currentItem.name, currentItem.type, currentItem.isReleaseNow)
            } else {
                null
            }
        }
        .map { filterMovieItem ->
            if (filterMovieItem.type == "other") {
                println("Movie is other Type")
                otherMovieItem.add(filterMovieItem)
            }
            filterMovieItem
        }.toList()
    return Pair(filterList, otherMovieItem)
}

核心需求:在判断!item.name.isNullOrEmpty() && !item.type.isNullOrEmpty() && item.isReleaseNow != null时,需要同时拿到当前项的下一项,添加额外条件。


解决方案

Kotlin中处理这种"同时访问当前项和下一项"的场景,有几种惯用方式:

方式1:使用windowed函数(推荐)

windowed是Kotlin标准库为集合提供的扩展函数,可直接生成包含当前项和后续项的窗口。参数size=2表示每个窗口包含2个连续元素,step=1表示每次移动1个位置,刚好遍历每个元素和它的下一项。

注意:最后一个元素没有下一项,可通过添加占位项或单独处理来覆盖所有元素。

示例代码:

private fun filterData(unFilteredMovieList: List<NewMovieItem>): Pair<List<FilterMovieItem>, MutableList<FilterMovieItem>> {
    val otherMovieItem = mutableListOf<FilterMovieItem>()
    val filterList = mutableListOf<FilterMovieItem>()

    // 生成当前项+下一项的窗口,最后补充最后一项+null的组合
    val windowedList = unFilteredMovieList.windowed(size = 2, step = 1, partialWindows = false)
        .map { (current, next) -> current to next }
        .plus(unFilteredMovieList.lastOrNull() to null)

    windowedList.forEach { (currentItem, nextItem) ->
        // 基础判断条件
        val baseCondition = !currentItem.name.isNullOrEmpty() && !currentItem.type.isNullOrEmpty() && currentItem.isReleaseNow != null
        // 结合下一项的额外判断(示例:下一项类型为action,或当前是最后一项)
        val extraCondition = nextItem?.type == "action" || nextItem == null

        if (baseCondition && extraCondition) {
            val filteredItem = FilterMovieItem(currentItem.name, currentItem.type, currentItem.isReleaseNow)
            filterList.add(filteredItem)
            if (filteredItem.type == "other") {
                otherMovieItem.add(filteredItem)
            }
        }
    }

    return Pair(filterList, otherMovieItem)
}

方式2:通过索引遍历

直接通过索引访问当前项和下一项,适合需要精细控制的场景:

private fun filterData(unFilteredMovieList: List<NewMovieItem>): Pair<List<FilterMovieItem>, MutableList<FilterMovieItem>> {
    val otherMovieItem = mutableListOf<FilterMovieItem>()
    val filterList = mutableListOf<FilterMovieItem>()

    for (i in unFilteredMovieList.indices) {
        val currentItem = unFilteredMovieList[i]
        val nextItem = if (i < unFilteredMovieList.lastIndex) unFilteredMovieList[i+1] else null

        val baseCondition = !currentItem.name.isNullOrEmpty() && !currentItem.type.isNullOrEmpty() && currentItem.isReleaseNow != null
        // 示例额外条件:下一项的screenNumber为空或不存在
        val extraCondition = nextItem?.screenNumber.isNullOrBlank()

        if (baseCondition && extraCondition) {
            val filteredItem = FilterMovieItem(currentItem.name, currentItem.type, currentItem.isReleaseNow)
            filterList.add(filteredItem)
            if (filteredItem.type == "other") {
                otherMovieItem.add(filteredItem)
            }
        }
    }

    return Pair(filterList, otherMovieItem)
}

方式3:使用withIndex()遍历

和索引遍历逻辑一致,同时获取索引和元素,写法更简洁:

private fun filterData(unFilteredMovieList: List<NewMovieItem>): Pair<List<FilterMovieItem>, MutableList<FilterMovieItem>> {
    val otherMovieItem = mutableListOf<FilterMovieItem>()
    val filterList = mutableListOf<FilterMovieItem>()

    unFilteredMovieList.withIndex().forEach { (index, currentItem) ->
        val nextItem = unFilteredMovieList.getOrNull(index + 1)

        val baseCondition = !currentItem.name.isNullOrEmpty() && !currentItem.type.isNullOrEmpty() && currentItem.isReleaseNow != null
        // 示例额外条件:下一项名称和当前项相同,或当前是最后一项
        val extraCondition = nextItem?.name == currentItem.name || nextItem == null

        if (baseCondition && extraCondition) {
            val filteredItem = FilterMovieItem(currentItem.name, currentItem.type, currentItem.isReleaseNow)
            filterList.add(filteredItem)
            if (filteredItem.type == "other") {
                otherMovieItem.add(filteredItem)
            }
        }
    }

    return Pair(filterList, otherMovieItem)
}

内容的提问来源于stack exchange,提问作者Compose Learner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 11:07:15