在另一个列表的 forEach 函数中过滤一个列表 - Kotlin

Filter a list inside forEach function of another list - Kotlin

我正在尝试过滤一个列表 return 它在另一个列表的映射函数中。

val userChoiceCategories = recommendedCategoryDb.find(RecommendedCategory::userId eq userId).toList()
    
    userChoiceCategories.forEach {
        //
        return articleDb.find().toList()
            .filter { article ->
                article.category != it.category.name
            }
    }

    return listOf()

我想显示除一个用户选择的所有其他类别的文​​章 在探索页面中显示它们。 forEach 循环只适用于列表中的第一项,我猜它会停止。对我哪里出错的地方有任何澄清吗?

Kotlin 有一个叫做 qualified returns, which means return statements inside lambdas (like the one passed to forEach) 的概念需要以不同的方式处理。

考虑以下示例。

这将只打印名字,然后退出(就像你的方法一样)和 return 1

fun printNames(names: List<String>): Int {
    names.forEach {
        println(it)
        return 1
    }
    return names.size
}

这将打印所有名称和 return 列表大小,但内部 return 毫无意义

fun printNames(names: List<String>): Int {
    names.forEach {
        println(it)
        return@forEach
    }
    return names.size
}

这也会打印所有的名字

fun printNames(names: List<String>): Int {
    names.forEach {
        println(it)
    }
    return names.size
}

这将只打印非空名称,这里的 return@forEach 就像普通 for 循环中的 continue

fun printNames(names: List<String>): Int {
    names.forEach {
        if( it.isEmpty() ) return@forEach
        println(it)
    }
    return names.size
}

那么这对您的问题有何影响?

我看到你的东西有两个问题:

  1. 立即退出循环的不合格return(如您在问题中所述)
  2. 事实是它没有累积应用过滤器(filter return过滤列表)

我还不完全清楚你还在尝试做什么,但是你发布的代码的固定版本看起来像这样(似乎是在尝试 return 做的文章列表与用户选择的类别不匹配)

    var result = articleDb.find().toList()

    userChoiceCategories.forEach { choice ->
        //
        result = result.filter { article ->
            article.category != choice.category.name
        }
    }

    return result

作为一种更紧凑的方式,如果您想 return 其类别与任何选定类别匹配的文章,您可以这样做(并且可以反转布尔逻辑或使用 filterNot 如果你想要的文章与类别列表不匹配)

    // find all articles whose category is in the user choice list
    return articleDb.find().toList().filter { article ->
        userChoiceCategories.any { choice ->
            article.category == choice.category.name
        }
    }
val userChoiceCategories = recommendedCategoryDb.find(RecommendedCategory::userId eq userId).toList()

val categoriesToOmit = userChoiceCategories.map { it.category.name }.toSet()

return articleDb.find().toList().filter { !categoriesToOmit.contains(it.category) }

更简洁的形式:

return recommendedCategoryDb
  .find(RecommendedCategory::userId eq userId).toList()
  .map { it.category.name }.toSet()
  .let { toOmit ->
    articleDb
      .find().toList()
      .filter { article -> article.category !in toOmit } 
  }