24

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 ) }
}

2 Answers 2

23

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 }
Sign up to request clarification or add additional context in comments.

9 Comments

This is not working if I use != . Is there a way to use with it?
The intersect extension function. Maybe is mandatory to use filterNot?
But then it isn't really an intersection, is it?
Yeah, I wrote a new function with filterNot called difference (it is the same, only changes filter to filterNot). You can add it to your reply if you want so it can help to more people!
Can test it on Monday.. you have two function calls nonetheless.. filterNot..any.. == or filter..none..== should make no difference..
|
12

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...

2 Comments

Flatmapping models to api won't produce a list of models. Switch the variables.
@EugenPechanec Oops of course. Answer edited, thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.