-1

我可以有一个像

 ["1", "2", "3", ".", "4", "."]

在我的分隔符第一次出现后,我希望删除重复项

就我而言,上面的列表应该变成

 ["1", "2", "3", ".", "4"]

我想要所有重复的“。” 第一次出现后删除。最好的方法是什么?

4

5 回答 5

3

您可以使用临时 MutableSet 轻松检查值是否重复。

fun <T> MutableList<T>.removeDuplicates(): Boolean {
    val set = mutableSetOf<T>()
    return retainAll { set.add(it) }
}

解释:MutableList.retainAll是一个函数,它删除 lambda 返回 false 的每个项目。将项目添加到 Set 时,如果该项目已存在于 Set 中,则返回 false。因此,每个唯一项目的第一次出现将返回 true,而后续出现将返回 false


编辑:在我看来,也许您只对具有重复项的特定分隔符条目感兴趣。在这种情况下,我会使用一个布尔值而不是一个集合来跟踪它是否已经被发现。我使用removeAll而不是retainAll使它更易于阅读。

fun <T> MutableList<T>.removeDuplicatesOf(delimiter: T): Boolean {
    var firstInstanceFound = false
    return removeAll { it == delimiter && firstInstanceFound.also { firstInstanceFound = true } }
}

说明:removeAll删除lambda 返回 true 的任何内容。由于逻辑短路,任何不是分隔符的东西都会在&&到达之后的部分之前返回 false。当找到第一个分隔符时,firstInstanceFound将为假,因此逻辑语句的计算结果为假。also分支也会被命中,因此对于firstInstanceFound找到的任何后续分隔符都是如此。

于 2020-06-16T22:10:30.400 回答
1

我找到了两种方法。第一个是最“Java”的:

// Setup values
val list = mutableListOf("1", "2", "3", ".", "4", ".")
val delim = "."

// Check if list is empty
val size = list.size - 1
if (size < 0) return

// Get first delim index
val firstMatch = list.indexOf(delim) + 1
if (firstMatch < 1) return

// Reverse-iterate the list until delim location
for (i in size downTo minOf(firstMatch, size)) {
    if (list[i] == delim) list.removeAt(i)
}

println(list)

这是较小的 Kotlin 风格的解决方案:

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

val firstMatch = list.indexOf(delim)
if (firstMatch < 0) return
val newList = list.filterIndexed { index, s -> s != delim || index == firstMatch }
println(newList)
于 2020-06-16T22:38:07.083 回答
0

最简单的方法是使用distinct()函数,它返回一个没有重复值的列表

val list = listOf('1', '2', '3', '.', '4', '.')
println(list.distinct()) // [1, 2, 3, ., 4]
于 2020-06-16T22:46:54.843 回答
0

要删除这些应用循环并将项目添加到新列表中。步骤

首先将列表转换为可变列表

 val list = listOf("1", "2", "3", ".", "4", ".")
 val mutablelist =list.toMutableList()

在此之后申请循环并将数据存储在新的输出列表中

  val outcominglist= ArrayList<String>()

 for(i in list){
    val item = mutablelist[0]
    mutablelist.removeAt(0)
    if(outcominglist.contains(item)){

    }
    else{
        outcominglist.add(item)
    }
 }

打印输出列表。

print(outcominglist)

第二种也是最简单的方法(使用 .distinct 方法)

 val list = listOf('1', '2', '3', '.', '4', '.')
 val newlist =list.distinct()
 print(newlist)
于 2020-06-17T02:33:04.503 回答
0

由于您使用的是 Kotlin,因此您拥有不可变数据类型和函数而没有副作用的优势。以下是如何在不向外部公开任何状态的函数中使用不可变列表来执行此操作,方法是使用fold()

val originalList = listOf("1", "2", "3", ".", "4", ".")

val (filteredList, _) = originalList.fold(
    Pair(emptyList<String>(), false)
) { (newList, found), item ->
    if (item == "." && !found) Pair(newList + item, true)
    else if (item == ".") Pair(newList, true)
    else Pair(newList + item, found)
}

println(filteredList)

结果:

[1, 2, 3, ., 4]

fold()获取一个初始累加器值,然后对列表的每个元素应用该函数,并在累加器运行时更​​新它。

在这里,我们将累加器设置Pair为一个空列表,我们将在其中构建新列表,以及一个布尔值,以跟踪我们是否已经看到.

对于原始列表的每个元素,我们返回一个新的对,将项目添加到新列表(如果需要)并更新我们是否已经看到.newList + item不会将该项目添加到不可变列表中,它会返回一个新的不可变列表,其中附加了该项目。因为Bool如果我们将跟踪.作为对的一部分,我们会将跟踪传递给每次迭代,因此不需要函数外部的临时变量来跟踪它。

最后,因为累积值是一个 Pair,我们使用解构来仅提取与 的对的累积列表(第一个值)val (filteredList, _) = pair

对于您的列表,返回的 Pair 值将如下所示:

  1. ([1], false)
  2. ([1, 2], false)
  3. ([1, 2, 3], false)
  4. ([1, 2, 3, .], true)
  5. ([1, 2, 3, ., 4], true)
  6. ([1, 2, 3, ., 4], true)
于 2020-06-17T02:40:35.840 回答