LunaVulpo
LunaVulpo

Reputation: 3221

how to filter list base on another list in kotlin/java?

I have two types FooApi and FooModel:

class FooApi (var aId) 
class FooModel(var mId)

Is a way to simplify below function which filter FooModel list base on FooApi list:

fun f(fooModelList: List<FooModel>, fooApiList: List<FooApi>) : List<FooModel> {
  return fooModelList.filter { fooApiList.map { it.aId }.contains ( it.mId ) }
}

Upvotes: 24

Views: 21925

Answers (2)

Roland
Roland

Reputation: 23262

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 }

Upvotes: 23

MajorShepard
MajorShepard

Reputation: 433

I would do something like

val apiList = listOf(FooApi(1), FooApi(2), FooApi(3))
val modelList = listOf(FooModel(1), FooModel(3))

val output = apiList.flatMap { api -> modelList.filter { api.id == it.id }}

Givin as output

[FooModel(id=1), FooModel(id=3)]

I don't know if the difference is significant...

Upvotes: 12

Related Questions