Упражнение, касающееся Kotlin Set

Описание задания:

Объявите функцию twoInThree (a: Set, b: Set, c: Set), которая возвращает набор всех элементов, содержащихся в точно два из трех заданных наборов a, b, c.

Мое решение:

fun main(args: Array<String>) {
    var a = setOf<Int>(1, 2, 5)
    var b = setOf<Int>(2, 7, 0)
    var c = setOf<Int>(3, 5)

    val result = twoInThree(a, b, c)
    println(result) // [2, 5]
}

fun twoInThree(a: Set<Int>, b: Set<Int>, c: Set<Int>): MutableSet<Int> {
    var results = mutableSetOf<Int>()
    var intersectOfAll = a.intersect(b).intersect(c)

    val aIntersectB = a.intersect(b)
    val aIntersectC = a.intersect(c)
    val bIntersectC = b.intersect(c)

    results.addAll(aIntersectB)
    results.addAll(aIntersectC)
    results.addAll(bIntersectC)

    results.removeAll(intersectOfAll)

    return results
}

Если получил тот же результат, что и инструктор, и попробовал с другими наборами. Он всегда возвращал ожидаемый результат. Итак, я полагаю, что мое решение формально правильное.

Но: Можно ли было решить задачу лучше?

1 ответ
1

Прежде чем перейти к другому возможному решению, я дам вам несколько предложений по вашему текущему коду:

  • Использовать val вместо var при любой возможности. Это возможно для всех переменных в вашем коде.

  • Нет необходимости указывать <Int> на setOf, Котлин может сам определить наиболее подходящий тип.

  • Функция twoInThree способен обрабатывать любые типы наборов, а не только целые. Для этого можно использовать параметр универсального типа.

    Измените метод на fun <T> twoInThree(a: Set<T>, b: Set<T>, c: Set<T>): MutableSet<T>

    И естественно также val results = mutableSetOf<T>()

  • Предпочитайте возвращать неизменяемые типы, если вам действительно не нужно делать иначе, в этом случае предпочитайте возвращать Set над MutableSet (вызывающим абонентам не нужно заботиться о том, что вы используете MutableSet в своей реализации)


Подход

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

Задание заключается в поиске элементов, которые существуют в ровно два из трех заданных наборов a, b, c.

Ваш подход хорош, в этом нет ничего плохого, но… Будет ли масштабироваться?

Если вы проверите элементы, которые существуют во всех трех наборах или ровно в одном наборе, это можно сделать довольно легко, возвращая различные пересечения, объединения и т. Д. Но что, если будет пять наборов?

Задание о ровно два из трех наборов.

Один, два, три.

Мы умеем считать!

Подсчитав количество появлений каждого элемента, мы можем выполнить итерацию по всем наборам (независимо от того, три, пять или двадцать) ровно один раз.

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

Итак, как это сделать?


Мой подход

Начните с создания списка всех наборов. listOf(a, b, c)

Затем просмотрите список и сопоставьте каждый набор со всеми его элементами. .flatMap { it } который также можно записать как .flatten()

Затем создайте группу элементов .groupingBy { it }

Затем создайте карту с подсчетом каждого элемента .eachCount()

listOf(a, b, c).flatten().groupingBy { it }.eachCount()

Это дает вам карту Map<Int, Int> где ключи — это элементы, а значения — количество раз, когда каждый элемент встречается.

Теперь вы можете отфильтровать эту карту и вернуть ключи, которые соответствуют вашим требованиям. .filter { it.value == 2 }.map { it.key }

Полный код:

val result = listOf(a, b, c).flatten()
     .groupingBy { it }
     .eachCount()
     .filter { it.value == 2 }
     .map { it.key }

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *