list - 当谓词为 true 时拆分列表

标签 list kotlin transformation

Kotlin 是否提供突变函数来在特定谓词为真时拆分列表?

在以下示例中,当元素为 . 时,应拆分列表。 。 结果应为 List<List<String>> 类型.

// input list
val list = listOf(
    "This is", "the", "first sentence", ".",
    "And", "now there is", "a second", "one", ".",
    "Nice", "."
)

// the following should be the result of the transformation
listOf(
    listOf("This is", "the", "first sentence"),
    listOf("And", "now there is", "a second", "one"),
    listOf("Nice")
)

我需要类似 list.splitWhen { it == "." } 的东西

最佳答案

Does Kotlin provide a mutation function to split a list when a specific predicate is true?

我听说过的最接近的是 partition() ,但我认为它不适用于您的情况。

我已经制作并简要测试了 3 个高阶扩展函数,它们给出了相同的预期输出。

解决方案 1:直接方法

inline fun List<String>.splitWhen(predicate: (String)->Boolean):List<List<String>> {
    val list = mutableListOf<MutableList<String>>()
    var needNewList = false
    forEach {
            string->
        if(!predicate(string)){
            if(needNewList||list.isEmpty()){
                list.add(mutableListOf(string))
                needNewList= false
            }
            else {
                list.last().add(string)
            }
        }
        else {
            /* When a delimiter is found */
           needNewList = true
        }
    }
    return list
 }

解决方案 2:基于配对的方法

inline fun List<String>.splitWhen(predicate: (String)->Boolean):List<List<String>> {
    val list = mutableListOf<List<String>>()
    withIndex()
        .filter { indexedValue ->  predicate(indexedValue.value) || indexedValue.index==0 || indexedValue.index==size-1} // Just getting the delimiters with their index; Include 0 and last -- so to not ignore it while pairing later on
        .zipWithNext() // zip the IndexValue with the adjacent one so to later remove continuous delimiters; Example: Indices : 0,1,2,5,7 -> (0,1),(1,2),(2,5),(5,7)
        .filter { pair-> pair.first.index + 1 != pair.second.index } // Getting rid of continuous delimiters; Example: (".",".") will be removed, where "." is the delimiter
        .forEach{pair->
            val startIndex = if(predicate(pair.first.value)) pair.first.index+1 else pair.first.index // Trying to not consider delimiters
            val endIndex = if(!predicate(pair.second.value) && pair.second.index==size-1) pair.second.index+1 else pair.second.index // subList() endIndex is exclusive
            list.add(subList(startIndex,endIndex)) // Adding the relevant sub-list
        }
    return list
}

解决方案 3:如果找到分隔符,则检查下一个值

inline fun List<String>.splitWhen(predicate: (String)-> Boolean):List<List<String>> =
foldIndexed(mutableListOf<MutableList<String>>(),{index, list, string->
    when {
        predicate(string) -> if(index<size-1 && !predicate(get(index+1))) list.add(mutableListOf()) // Adds  a new List within the output List; To prevent continuous delimiters -- !predicate(get(index+1))
        list.isNotEmpty() -> list.last().add(string) // Just adding it to lastly added sub-list, as the string is not a delimiter
        else -> list.add(mutableListOf(string)) // Happens for the first String
    }
    list})

只需调用list.splitWhen{it=="delimiter"}。解决方案 3 看起来更有语法糖。除此之外,您还可以进行一些性能测试来检查哪一个性能良好。

注意:我做了一些简短的测试,您可以通过Kotlin Playground查看。或通过 Github gist .

关于list - 当谓词为 true 时拆分列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65140871/

相关文章:

android - 数据绑定(bind)和包含的布局 : Cannot find setter attribute for onClick

java - fragment 未显示在 Android 导航组件中

opencv - 几个透视变换的矩阵

javascript - 仅变换 Path2D 的样式

c++ - 俯仰偏航,角度独立

c++ - 如何在迭代 boost::intrusive::list 时删除

Java - 将对象列表映射到具有其属性属性值的列表

python - 提取一串句子中的地点和出版商

json - Kotlin Moshi 从 Assets 加载 Json

python - 在遍历列表时如果字符串不在项目中则计算一次 - python 3.x