如何迭代字符列表并比较不同的元素

时间:2018-11-19 12:16:07

标签: kotlin

我有一个要处理的字符串列表,所以可以说

val List<String?> = listOf("Q", NULL, "W", "E", NULL, "E", "E", "R", "R", "T") [sic]

我想对此进行处理,以便可以在相邻位置有两个匹配字符串的情况下应用谓词,并返回不可为空的字符串的列表。

扩展名的方法签名将为

fun <T : Any> List<T?>.processList(action: (T) -> T): List<T>

让我这次的谓词是在重复的第一个字符串中添加“陷阱”,然后删除第二个,因此在这种情况下,我将以

结尾
ListOf("Q", "W", "Egotcha", "E", "Rgotcha", "T")

我可以很容易地以老式的方式进行while循环

遵循这些原则的混乱版本

val nL : ArrayList<T> = ArrayList<T>()
var indexThis : Int = 0
while ( indexThis < intermediate.size-1 ) {
    if (intermediate[indexThis] != intermediate[indexThis + 1]) {
        nL.add(intermediate[indexThis]!!)
        indexThis += 1 }
    else {
        nL.add(processList(intermediate[indexThis]!!))
        indexThis += 2 }
}

这距离完成文章还有很长的路要走,但是这是我试图使过程清晰明了的尝试...

但是我正在努力以更实用的方式开始做它

所以我可以发现我可能想从

开始
 this.filter {a -> a != null}

但是然后我看不到下一步要去哪里?那么我能想到的唯一方法是forEachIndexed,但是我对此的尝试似乎非常复杂。我确定我已经看到人们比较地图中List中的项目的例子了吗?

我的最后思路是

.map{b -> b?.run{b ...  processList (b)}}

但这似乎很不正确

谁能指出我正确的方向?

2 个答案:

答案 0 :(得分:1)

这是第一步,这在功能上有些困难,因为在累积结果时必须保持某些状态。

fun <T> List<T?>.processList(action: (T) -> T): List<T> where T: Comparable<T> {
    data class Accumulator(val resultList: MutableList<T> = mutableListOf(), var previousWasDupe: Boolean = false)

    return this.asSequence()
               .filterNotNull()
               .windowed(2, partialWindows = true).fold(Accumulator()) { accum, value ->
        if (accum.previousWasDupe) {
            // skip this one that was already consumed in the dupe
            accum.previousWasDupe = false
        } else if (value.size < 2 || value[0] != value[1]) {
            accum.resultList.add(value[0])
            accum.previousWasDupe = false  //  already is false, you could delete this line, here for clarity
        } else {
            accum.resultList.add(action(value[0]))
            accum.previousWasDupe = true
        }
        accum
    }.resultList

}

针对您的测试用例:

val items = listOf("Q", null, "W", "E", null, "E", "E", "R", "R", "T")
println(items.processList { it + "gotcha" })

// prints "[Q, W, Egotcha, E, Rgotcha, T]"

您也可以使用一个不可变的累加器(我不喜欢它是可变的,但是它会更好地运行),但是鉴于状态是内部的,因此毫无意义地采取这种攻击功能。无论是作为序列(书面形式)还是与副本一起使用,效果都更好,取决于列表的大小,如果不进行性能测试,很难说。

请注意,我还确保<T>项是Comparable,以便我们可以确定==达到了预期的效果,否则您真的不知道自己收到了该功能甚至可以处理的事情。


有趣的是,不可变版本:

fun <T> List<T?>.processListImmutable(action: (T) -> T): List<T> where T: Comparable<T> {
    data class Accumulator(val resultList: List<T> = emptyList(), val previousWasDupe: Boolean = false)

    return this.asSequence()
        .filterNotNull()
        .windowed(2, partialWindows = true).fold(Accumulator()) { accum, value ->
            if (accum.previousWasDupe) {
                Accumulator(accum.resultList, false) // could also be: accum.copy(previousWasDupe = false)
            } else if (value.size < 2 || value[0] != value[1]) {
                Accumulator(accum.resultList + value[0], false)
            } else {
                Accumulator(accum.resultList + action(value[0]), true)
            }
        }.resultList
}

输入要解决的一个极端情况:

val items = listOf("Q", null, "W", "E", null, 
                   "E", "E", "R", "R", "T", 
                   "Z", "Z", "Zgotcha")  // <--- this is the trap

应返回:

[Q, W, Egotcha, E, Rgotcha, T, Zgotcha, Zgotcha]

而不是:

[Q, W, Egotcha, E, Rgotcha, T, Zgotchagotcha]

答案 1 :(得分:0)

尝试下一个代码:

IStringLocalizer