Удаление элементов из MutableList с помощью Kotlin - PullRequest
0 голосов
/ 17 июня 2020

У меня мог бы быть список вроде

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

После первого появления моего разделителя я хочу, чтобы дубликаты были удалены

В моем случае приведенный выше список должен стать

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

Мне нужны все дубликаты "." удаляется после первого появления. Как лучше всего?

Ответы [ 5 ]

3 голосов
/ 17 июня 2020

Вы можете использовать временный MutableSet, чтобы легко проверить, не дублируются ли значения.

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

Объяснение: MutableList.retainAll - это функция, которая удаляет каждый элемент, для которого лямбда возвращает false. Когда вы добавляете элемент в набор, он возвращает false, если элемент уже существует в наборе. Таким образом, первое вхождение каждого уникального элемента вернет истину, в то время как последующие вхождения вернут ложь


Изменить: мне пришло в голову, что, возможно, вас интересует только конкретная запись разделителя c, имеющая дубликаты. В этом случае вместо Set я бы использовал только логическое значение, чтобы отслеживать, найдено ли оно еще. И я использую removeAll вместо retainAll, чтобы было легче читать.

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

Объяснение: removeAll будет удалить все, для чего лямбда возвращает true. Из-за логического короткого замыкания все, что не является разделителем, вернет false до того, как будет достигнута часть после &&. Когда будет найден первый разделитель, firstInstanceFound будет ложным, поэтому логический оператор оценивается как ложный. Также попадает в ветвь also, поэтому firstInstanceFound будет истинным для любых последующих найденных разделителей.

1 голос
/ 17 июня 2020

Я нашел два пути. Первый - это самый '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)
0 голосов
/ 17 июня 2020

Поскольку вы используете 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 пустого list, в котором мы создадим новый список и логическое значение, чтобы отслеживать, видели ли мы уже ..

Для каждого элемента исходного списка мы возвращаем новую пару, добавляя элемент в новый список (при необходимости) и обновление, видели ли мы уже .. newList + item не добавляет элемент в неизменяемый список, он возвращает новый неизменяемый список с добавленным к нему элементом. Поскольку мы передаем отслеживание Bool, если мы видели . как часть пары на каждой итерации, нет необходимости во временной переменной вне функции для отслеживания этого.

Наконец, поскольку накопленные value - это пара, мы используем деструктурирование , чтобы извлечь только накопленный список (первое значение) пары с 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)
0 голосов
/ 17 июня 2020

Чтобы удалить их, примените циклы for и добавьте элементы в новый список. Шаги

Сначала Преобразуйте список в изменяемый список

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

после этого примените l oop и сохраните данные в новом списке исходящих

  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)
0 голосов
/ 17 июня 2020

Самый простой способ сделать это - использовать функцию distinct(), которая возвращает список без повторяющихся значений

val list = listOf('1', '2', '3', '.', '4', '.')
println(list.distinct()) // [1, 2, 3, ., 4]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...