Пересечение двух списков с сохранением повторяющихся значений в Котлине - PullRequest
0 голосов
/ 09 декабря 2018

Я хочу найти количество общих элементов между двумя списками без удаления дубликатов.

Например:


вход: [1, 3, 3] & [4, 3, 3]

выход: 2, поскольку общими элементами являются [3, 3]


вход: [1, 2, 3] & [4, 3, 3]

выход: 1, поскольку общими элементами являются [3]


Если бы я использовалКоллекции Kotlin пересекаются , в результате получается набор, который не позволит мне считать дубликаты значений.

Я нашел (для Python) this , который по-разному обрабатывает дубликаты, и this , что привело меня к использованию этой реализации, где a и b являются списками:

val aCounts = a.groupingBy { it }.eachCount()
val bCounts = b.groupingBy { it }.eachCount()
var intersectionCount = 0;
for ((k, v) in aCounts) {
    intersectionCount += Math.min(v, bCounts.getOrDefault(k, 0))
}

Однако, будучи новичком в Kotlin, я задаюсь вопросом, есть ли более "Kotlin-y" способ сделать это - что-то, использующее преимущества всех коллекций Kotlinфункциональность?Может быть, что-то, что избегает явной итерации?

1 Ответ

0 голосов
/ 09 декабря 2018

This:

val a = listOf(1, 2, 3, 3, 4, 5, 5, 5, 6)
val b = listOf(1, 3, 3, 3, 4, 4, 5, 6, 6, 7)

var counter = 0

a.intersect(b).forEach { x -> counter += listOf(a.count {it == x}, b.count {it == x}).min()!! }

println(counter)

напечатает

6

Он использует пересечение 2 списков и, перебирая каждый из его элементов, добавляет к счетчику минимальное количествовхождения предмета в оба списка.С помощью этого импорта:

import kotlin.math.min

вы можете избежать создания списка на каждой итерации и упростить до:

a.intersect(b).forEach { x-> counter += min(a.count {it == x}, b.count {it == x}) } 

Предоставлено Арджаном, более элегантный способ подсчета суммы:

val result = a.intersect(b).map { x -> min(a.count {it == x}, b.count {it == x}) }.sum()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...