【问题标题】:Convert Java Frequency Sort to Kotlin将 Java 频率排序转换为 Kotlin
【发布时间】:2021-10-11 04:40:36
【问题描述】:

我需要按列表中出现的次数 (DESC) 对 List<String> 进行排序,并从那里删除重复项。我用java写了这个工作算法:

 private List<String> sortByFrequency(List<String> sequence) {
    return
            sequence.stream()
                    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                    .entrySet().stream()
                    .sorted(Map.Entry.<String, Long>comparingByValue(Comparator.reverseOrder())
                            .thenComparing(Map.Entry.comparingByKey()))
                    .map(Map.Entry::getKey)
                    .collect(Collectors.toList());
}

但它不适用于 Kotlinkotlin code

因为我得到以下异常:

    Type inference failed. Expected type mismatch: 
    required:
    Collector<in String!, Any!, Long!>!
    found:
    Collector<String!, *, Long!>!

并且无法弄清楚如何解决它。可以告诉我吗?

【问题讨论】:

  • 如果我省略了收集器的显式输入,它对我有用。

标签: java algorithm sorting kotlin frequency


【解决方案1】:

让 Kotlin 为您找出类型。除非需要,否则不要指定类型参数。 Kotlin 会尽力找到正确的类型。

只有一个地方需要指定类型参数,那就是Map.Entry.comparingByValue调用。

这样编译:

fun sortByFrequency(sequence: List<String>): List<String?>? {
    return sequence.stream()
        .collect(Collectors.groupingBy({ it }, Collectors.counting()))
        .entries.stream()
        .sorted(
            Map.Entry.comparingByValue<String, Long>(Comparator.reverseOrder())
                .thenComparing(Map.Entry.comparingByKey())
        )
        .map { it.key }
        .collect(Collectors.toList())
}

但是,代码仍然感觉非常 Java 风格。 IMO,这是更惯用的 Kotlin:

fun sortByFrequency(sequence: List<String>): List<String> {
    val comparator = compareByDescending<Map.Entry<String, Int>> { it.value }
        .thenBy { it.key }
    return sequence.groupingBy { it }.eachCount().entries
        .sortedWith(comparator).map { it.key }
}

注意groupingByeachCount 的使用。

【讨论】:

  • 嘿!非常感谢您的回答,但我得到了 return sequence.groupingBy { it }.eachCount().entries raw 的编译错误:类型推断失败:没有足够的信息来推断 fun !> 中的参数 U 比较(keyExtractor: ( (T!) → U!)! ) : 比较器!请明确指定。
  • @WLDRMND 您似乎没有完全复制我的答案。无论如何,我只是找到了一个更简洁、更 kotliny 的版本。请记住,您需要为 compareByDescending 指定类型参数(如果您正在谈论答案的先前版本,则为 comparing)。
  • 非常感谢您的回复,我会尝试更多地了解这个主题,它有效:)
【解决方案2】:

问题在于*Any 的含义不同。它们被视为不同的类型,因此编译失败。事实上,* 在 Kotlin 中可以表示 in Nothingout Any?,具体取决于上下文。

有关该主题的更多信息: https://kotlinlang.org/docs/generics.html#star-projections

在您的情况下,Kotlin 应该能够为您推断出正确的收集器类型,因此可以将它们排除在外。

【讨论】:

  • 如果你了解 Java,Any 等价于 Object(可空性除外),一个包含所有可能对象的类型;而* 是等价于? 的通配符,指的是可能包含也可能不包含任意对象的未知类型。
猜你喜欢
  • 2018-11-26
  • 1970-01-01
  • 2017-07-04
  • 2013-05-16
  • 1970-01-01
  • 2010-12-01
  • 2012-08-27
  • 2021-08-16
  • 2021-02-03
相关资源
最近更新 更多