【问题标题】:Kotlin - Filter/Map from two CollectionsKotlin - 来自两个集合的过滤器/映射
【发布时间】:2018-08-21 18:58:09
【问题描述】:

是否可以根据所需的条件匹配来过滤和映射两个集合,如下所示:

fun main(args: Array<String>) {
    val selectedDates = listOf("2018-08-12", "2018-08-13", "2018-08-14")

    val expenses = listOf(Expense("Food", "2018-08-12"),
    Expense("Transportation", "2018-08-15"),
    Expense("Misc.", "2018-08-13"),
     Expense("Uber", "2018-08-12"),
    Expense("Clothing", "2018-08-16"))

    val listOfExpensesInSelectedDate = mutableListOf<Expense>()

    for (date in selectedDates){
        listOfExpensesInSelectedDate.addAll(expenses.filter { it.date==date })

    }
    println(listOfExpensesInSelectedDate)

}

data class Expense(
        val expense:String,
        val date: String
)

提供上面给定的代码,我试图返回与另一个字符串列表中的日期匹配的费用列表。在上面的示例中,我同时使用了 for Loop 和 filter 函数来获得我想要的结果。但是是否可以避免 for 循环和过滤器并在单行代码中映射两个集合?

【问题讨论】:

    标签: collections kotlin


    【解决方案1】:

    您可以只使用in 进行过滤:

    val listOfExpensesInSelectedDate = expenses.filter { it.date in selectedDates }
    

    编辑:自从hotkey发布了关于最佳解决方案的评论,我已经在我的电脑上尝试过,任何有兴趣的人也可以尝试一下:

    (1st) 我发布的答案:

    val start = Date().time
    for (i in 1..10000) {
        val listOfExpensesInSelectedDate = expenses.filter { it.date in selectedDates }
    }
    val end= Date().time
    
    println(end - start)
    

    平均时间结果:26ms (23ms-35ms)

    (2nd) 我对热键建议使用集合的回答:

    val start = Date().time
    for (i in 1..10000) {
        val expSet = selectedDates.toSet()
        val listOfExpensesInSelectedDate = expenses.filter { it.date in expSet }
    }
    val end= Date().time
    
    println(end - start)
    

    平均时间结果:70ms (50ms-86ms)

    (3d) 热键答案:

    val start = Date().time
    for (i in 1..10000) {
        val groups = expenses.groupBy { it.date }
        val listOfExpensesInSelectedDate = selectedDates.flatMap { groups[it].orEmpty() }
    }
    val end= Date().time
    
    println(end - start)
    

    平均时间结果:100ms (74ms-150ms)

    【讨论】:

    • 哇,谢谢。这是迄今为止我找到的最简洁的解决方案
    • @dey 这是 my 的答案,与 OP 的沟通是我的。不需要中间代表。删除您的评论
    • 请注意,这不是最佳解决方案,因为它每次都会遍历seectedDates 来检查谓词。要改进它,请将selectedDates 转换为集合。
    • @hotkey 迭代不会随着集合而消失。由于该集合是无序的,因此情况可能会更糟。
    • @mTak,大多数集合都有常数,O(1) 时间进行 contains 检查,而列表在 O(n) 最坏情况下做到这一点。带有大 selectedDates 的测试会证明这一点。
    【解决方案2】:

    您可以通过首先将expensesdate 分组,然后选择并合并在selectedDates 中具有键的组来简化和优化您的代码,如下所示:

    val selectedDates = listOf("2018-08-12", "2018-08-13", "2018-08-14")
    val expenses: List<Expense> = TODO("content omitted")
    
    val groups = expenses.groupBy { it.date }
    val listOfExpensesInSelectedDate = selectedDates.flatMap { groups[it].orEmpty() }
    

    请参阅:groupByflatMap

    【讨论】:

    • 它给出了以下错误:Error:(20, 54) Kotlin: Type inference failed: inline fun Iterable.flatMap(transform: (T) -> Iterable):List 不能应用于接收者:List 参数:((String) -> List?)
    • @Econ_newbie,抱歉,修复了这个例子,添加了一个备用密钥以防密钥丢失:groups[it].orEmpty()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-04
    • 2021-12-05
    • 1970-01-01
    • 2016-08-01
    • 2017-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多