Вычтите два списка в Kotlin, используя пользовательскую функцию равенства - PullRequest
0 голосов
/ 04 февраля 2019

У меня есть два списка, и я хочу получить список, содержащий только элементы в первом списке, которых нет во втором.Проблема в том, что мне нужно указать пользовательский equal при вычитании.Предположим, я хочу использовать одно из полей в записях списков.Допустим, id.

Я реализовал это следующим образом:

list1.filter { log -> list2.none { it.id == log.id } }

или

val projection = logEntries.map { it.id }
list1.filter { it.id !in projection }

Есть ли лучший способ сделать это?Обратите внимание, что я не могу установить новый метод equal для класса.

Ответы [ 3 ]

0 голосов
/ 04 февраля 2019

Другой подход?

fun main() {

    val list1 = listOf(0, 1, 2, 3, 4, 5)
    val list2 = listOf(2,3,4)

    println(list1.filterNotIn(list2))
}

fun <T> Collection<T>.filterNotIn(collection: Collection<T>): Collection<T> {
    val set = collection.toSet()
    return filterNot { set.contains(it) }
}

Вывод: [0, 1, 5]

0 голосов
/ 04 февраля 2019

То, как вы делаете это нормально, но когда списки становятся больше, вы можете захотеть сделать это:

Вы можете сделать процесс более эффективным, превратив свой список ссылок (list2) в наборfirst.

val referenceIds = list2.distinctBy { it.id }.toSet()

list1.filter { it.id !in referenceIds }

Фон:

ArrayList, который вы, скорее всего, используете, имеет временную сложность O (n), когда вы проверяете, является ли элементсодержится.Таким образом, если список станет больше, это займет больше времени.

A HashSet, с другой стороны, имеет временную сложность O (1) при проверке, содержится ли элемент.Итак, если list2 станет больше, оно не станет медленнее.

0 голосов
/ 04 февраля 2019

Согласно комментариям, нет встроенного способа сделать это.(Вероятно, не по какой-либо фундаментальной причине; просто потому, что никто не видел в этом необходимости.)

Однако вы можете легко добавить ее самостоятельно.Например, вот ваше первое предложение, преобразованное в функцию расширения:

fun <T, R> Collection<T>.minus(elements: Collection<T>, selector: (T) -> R?)
    = filter{ t -> elements.none{ selector(it) == selector(t) } }

Затем вы можете вызвать его так же, как и встроенная функция:

list1.minus(list2){ it.id }

(Возможно, есть более эффективные реализации, но это иллюстрирует идею.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...