Kotlin:遍历列表并在索引处添加项目

时间:2018-08-10 13:11:38

标签: foreach kotlin iterator

我有一个(可变的)物品清单。我想遍历此列表并检查每个项目的特定条件。满足条件后,我要在特定索引处插入(而不是替换)新项目。
在Kotlin中,最优雅的方法是什么?
附言我还没有代码示例,因为我想不出一个好方法。

编辑:用例:我想为特定项目组的列表视图添加标题。

4 个答案:

答案 0 :(得分:4)

如果您有可变列表,则可以获取其可变的listIterator并在迭代过程中使用该迭代器修改列表。

例如,在每个项目之后的 后面插入一个字符串,该字符串表示一个偶数:

val list = mutableListOf("1", "2", "3", "4")

val iterator = list.listIterator()
for (item in iterator) {
    if (item.toInt() % 2 == 0) {
        iterator.add("^ That was even")
    }
}

list.forEach { println(it) }    

或在当前字符串之前 之前插入字符串:

val iterator = list.listIterator()
for (item in iterator) {
    if (item.toInt() % 2 == 0) {
        iterator.previous()
        iterator.add("Next will be even:")
        iterator.next()
    }
}

list.forEach { println(it) }

答案 1 :(得分:1)

正如您说的那样,您遍历列表,也许flatMap对您来说是一件好事(在本例中,我在奇/偶元素之后添加了“奇”,“偶”):

val list = listOf("1", "2", "3", "4")
val newList = list.flatMap {
      // well... actually your conditions...
      when (it.toInt() % 2) {
        0 -> listOf(it, "<-- that was even" /*, whatever you want to add after it */)
        else -> listOf(it, "<-- that was odd" /*, whatever you want to add after it */)
      }
    }

现在这将为您返回一个新列表,其中包含您构造的元素,例如

[1, <-- that was odd, 2, <-- that was even, 3, <-- that was odd, 4, <-- that was even]

这样,您不一定需要可变列表。而且您相当快地掌握了列表中的内容(顺序/其他)。

如果您真的想保留可变列表并使用它,则需要确保在操作列表时不要更改列表,否则会得到ConcurrentModificationException。 另一方面,这意味着您需要在要插入事物的位置保留索引。插入索引后,保留索引将无效,但是如果保留索引中的任何一个高于先前添加的保留索引,则该索引将无效。除非您也移动了光标(即,将先前添加的元素的数量添加到索引中)。然后,这很容易将它们向后插入。下面是一个示例,其中列表必须与地图的键匹配,并将插入其值:

val list = mutableListOf("1", "2", "3", "4", "5", "6")

val itemsToInsertAfterMatch = mapOf("1" to "odd 1", "2" to "even", "3" to "odd", "4" to "ev4n")
list.mapIndexedNotNull { index, s -> itemsToInsertAfterMatch[s]?.let { index to it } }
    .reversed() // actually this ensures that we are operatoring on a separate list while we will add elements later
    .forEach { list.add(it.first, it.second) }

还是,我不推荐。如果您不必(以及谁强迫您?),我不会使用这样的构造。而是隐藏了正在发生的事情(例如,什么与什么匹配?什么时候插入了什么?)。

以上所有解决方案均未解决找不到元素的情况(例如indexOf返回-1itemsToInsertAfterMatch[s] == null)。尽管添加这种情况应该足够容易。

请注意,如果您要插入的内容是静态的,则带有索引的@mTaks解决方案当然要容易些,然后要使用上面介绍的映射。根据您的病情复杂程度,他们自己的指数将无法满足您的需求。而且我只能建议您改用flatMap。回来时更容易阅读。 indices / mapIndexed解决方案宁愿隐藏正在发生的事情。您可能需要解密,每次回到它。您甚至都不考虑索引,那么为什么要打扰呢?但这也许只是我的意见;-)

答案 2 :(得分:0)

这是我的方法:

val list = mutableListOf("ab", "CD", "ef", "gH")

list.indices
        .filter { list[it].toLowerCase() == list[it] }
        .mapIndexed { index, it -> it + index }
        .forEach { list.add(it, "XX") }

list.forEach { println(it)  }

将打印:XX ab CD XX ef gH

条件是,如果list元素全部为小写,则在其前面插入元素“ XX”。

如果您只关注优雅,或者您出于学术或研究原因想探索Kotlin的功能,那很好,但是我不确定总是花哨的方式是最有效的方式。
为什么不使用传统的while循环:

var index = 0

while (index < list.size) {
    if (list[index].toLowerCase() == list[index]) {
        list.add(index, "XX")
        index++
    }

    index++
}

这不是花哨的,但可以肯定的是,它比花哨的方法更有效,甚至更有效。

答案 3 :(得分:0)

我用groupBy

解决了
val map = mutableList.map {
    val groupItems = it.groupBy { (it as ListItem).section}
    val mappedItems = mutableListOf<ListBaseItem>()
    groupItems.forEach { section, items ->
        mappedItems.add(ListHeaderItem(section, section))
        mappedItems.addAll(items)
    }
    mappedItems
}