Kotlin: Find Count из вложенного набора в List (более функциональный подход)
Ниже функция создает карту, получает количество пассажиров, где пассажиры находятся> minTrips. Код работает совершенно нормально. Пожалуйста, смотрите ниже
fun List<Trip>.filter(minTrips : Int): Set<Passenger> {
var passengerMap: HashMap<Passenger, Int> = HashMap()
this.forEach { it: Trip ->
it.passengers.forEach { it: Passenger ->
var count: Int? = passengerMap.get(it)
if (count == null) {
count = 1
passengerMap.put(it, count)
} else {
count += 1
passengerMap.put(it, count)
}
}
}
val filteredMinTrips: Map<Passenger, Int> = passengerMap.filterValues { it >= minTrips }
println (" Filter Results = ${filteredMinTrips}")
return filteredMinTrips.keys
}
Хотя это написано на Kotlin, похоже, что код сначала был написан на Java, а затем преобразован в Kotlin. Если бы это было действительно написано на Kotlin, я уверен, что это не было бы так много строк кода. Как я могу уменьшить строки кода? Каков был бы более функциональный подход для решения этой проблемы? Какие функции или функции я могу использовать для извлечения набора пассажиров, где пассажиры находятся> minTrips? Это слишком много кода и кажется сумасшедшим. Любые указатели были бы полезны здесь.
2 ответа
Один из способов сделать это - воспользоваться плоской картой и группировкой вызовов Kotlin. Создав список всех пассажиров во всех поездках, вы можете сгруппировать их, сосчитать и вернуть тех, у которых число превышает определенное.
Предполагая, что у вас есть такие классы данных (только важные детали):
data class Passenger(val id: Int)
data class Trip(val passengers: List<Passenger>)
Я был в состоянии написать это:
fun List<Trip>.frequentPassengers(minTrips: Int): Set<Passenger> =
this
.flatMap { it.passengers }
.groupingBy { it }
.eachCount()
.filterValues { it >= minTrips }
.keys
Это хорошо, потому что это одно выражение. Проходя через это, мы смотрим на каждого Trip
и извлечь все его Passengers
, Если бы мы только что сделали map
здесь мы бы List<List<Passenger>>
, но мы хотим List<Passenger>
поэтому мы планируем, чтобы достичь этого. Далее мы groupBy
Passenger
сами объекты, и вызов eachCount()
на возвращенном объекте, давая нам Map<Passenger, Int>
, Наконец, мы отфильтровываем карту по интересующим нас Пассажирам и возвращаем набор ключей.
Обратите внимание, что я переименовал вашу функцию, List
уже есть filter
на нем, и хотя подписи разные, я нашел это запутанным.
По сути, вы хотите подсчитать количество поездок для каждого пассажира, поэтому вы можете поместить всех пассажиров в список, а затем сгруппировать их по ним, а затем подсчитать количество происшествий в каждой группе:
fun List<Trip>.usualPassengers(minTrips : Int) = // 1
flatMap(Trip::passengers) // 2
.groupingBy { it } // 3
.eachCount() // 4
.filterValues { it >= minTrips } // 5
.keys // 6
Объяснение:
- тип возврата
Set<Passenger>
можно сделать вывод this
может быть опущен, список формы[p1, p2, p1, p5, ...]
возвращается- Группировка создана, которая выглядит следующим образом
[p1=[p1, p1], p2=[p2], ...]]
- количество случаев в каждой группе будет подсчитано:
[p1=2, p2=1, ...]
- все элементы со значениями, которые меньше
minTrips
будет отфильтровано - все оставленные ключи будут возвращены
[p1, p2, ...]
p1...pn
Пассажирские экземпляры