Issue
I am trying to filter a list and return it inside map function of another list.
val userChoiceCategories = recommendedCategoryDb.find(RecommendedCategory::userId eq userId).toList()
userChoiceCategories.forEach {
//
return articleDb.find().toList()
.filter { article ->
article.category != it.category.name
}
}
return listOf()
I want to display articles from all other categories except the one user has selected to show them in Explore page. The forEach loop only works for the first item in the list I guess and it stops. any clarifications where I'm going wrong?
Solution
Kotlin has a concept called qualified returns, which means return statements inside lambdas (like the one passed to forEach
) need to be handled differently.
Consider the following examples.
This will print the first name only, then exit (like your method) and return 1
fun printNames(names: List<String>): Int {
names.forEach {
println(it)
return 1
}
return names.size
}
This will print all the names and return the list size, but the inner return is pointless
fun printNames(names: List<String>): Int {
names.forEach {
println(it)
return@forEach
}
return names.size
}
This will also print all the names
fun printNames(names: List<String>): Int {
names.forEach {
println(it)
}
return names.size
}
This will print only the non-empty names, the return@forEach
here acts like a continue
in a normal for loop.
fun printNames(names: List<String>): Int {
names.forEach {
if( it.isEmpty() ) return@forEach
println(it)
}
return names.size
}
So how does this affect your question?
There are two problems I see with what you have:
- the un-qualified return that exits the loop immediately (as you noted in the question)
- the fact that it doesn't apply the filters cumulatively (filter returns the filtered list)
It's not entirely clear to me what you're trying to do still, but a fixed version of the code you posted would look like this (seems to be trying to return a list of articles that do not match the user choice categories)
var result = articleDb.find().toList()
userChoiceCategories.forEach { choice ->
//
result = result.filter { article ->
article.category != choice.category.name
}
}
return result
As a more compact way of doing it, if you wanted to return articles whose category matches any of the selected categories you could do something like this (and could invert the boolean logic or use filterNot
if you want the articles that do not match the list of categories)
// 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
}
}
Answered By - Tyler V
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.