It looks ok to me. I would only change some minor things (not required though), so that it ends up something like the following:
fun List<FooModel>.f(fooApiList: List<FooApi>) = filter { m -> fooApiList.any { it.aId == m.mId } }
Some reasons why I did it this way:
- I think that filtering is always applied on a list of
FooModels, right? (that is the reason for the extension function narrowing the type to List<FooModel>)
- You are not interested in the mapped object of fooApiList, so that is why I used
any instead; the nice benefit there also is that now both values that are compared are next to each other
- summarizing everything can be said so easily, you can even omit the method body (and therefore return type, return statement, etc.)
Still, that's nearly the same as you did already... Just a bit less code and a rearrangement... Calling it by the way would look like:
val listA : List<FooModel> = TODO()
val listB : List<FooApi> = TODO()
val containedList = listA.f(listB)
If you require such a construct more often, maybe the following more generic solution is helpful:
fun <T, U> List<T>.intersect(uList: List<U>, filterPredicate : (T, U) -> Boolean) = filter { m -> uList.any { filterPredicate(m, it)} }
Which you can then also use like:
val containedList = listA.intersect(listB) {
a, b -> a.aId == b.mId
}
Then your f again might even look just like:
fun List<FooModel>.f(fooApiList: List<FooApi>) = intersect(fooApiList) { a, b -> a.mId == b.aId }