Kotlin:从列表中的嵌套集中查找计数(更实用的方法)

Kotlin: Find Count from Nested set in List (more functional approach)

下面的函数创建一个地图,获取乘客数量> 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 编写的,我相信这不会有这么多行代码。如何减少代码行数?什么是解决这个问题的更有效的方法?我可以使用哪些函数或函数直接在 Passengers are > minTrips 的位置提取 Passengers Set?这是太多的代码,看起来很疯狂。任何指针在这里都会有所帮助。

您基本上想计算每位乘客的行程,因此您可以将所有乘客放在一个列表中,然后按他们分组,然后计算每组中的出现次数:

fun List<Trip>.usualPassengers(minTrips : Int) = // 1
        flatMap(Trip::passengers) // 2
        .groupingBy { it } // 3
        .eachCount() // 4
        .filterValues { it >= minTrips } // 5
        .keys // 6

解释:

  1. return类型Set<Passenger>可以推断
  2. this 可以省略,[p1, p2, p1, p5, ...] 形式的列表是 returned
  3. 创建了一个Grouping,看起来像这样[p1=[p1, p1], p2=[p2], ...]]
  4. 将计算每组中出现的次数:[p1=2, p2=1, ...]
  5. 所有小于minTrips的元素将被过滤掉
  6. 剩下的所有键都将 returned [p1, p2, ...]

p1...pn 是 Passenger 实例

实现此目的的一种方法是利用 Kotlin 的平面图和分组调用。通过创建所有行程中所有乘客的列表,您可以对他们进行分组、计数,以及 return 超过一定数量的乘客。

假设您有这样的数据 类(仅基本细节):

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 对象本身,并在 returned 对象上调用 eachCount(),给我们一个 Map<Passenger, Int>。最后,我们将地图过滤掉我们感兴趣的乘客,以及 return 键集。

请注意,我重命名了您的函数,List 上已经有一个 filter,尽管签名不同,但我发现它很混乱。