Home > Enterprise >  How can use filter and contains with multi-ArrayList in Kotlin so I only have elements which match t
How can use filter and contains with multi-ArrayList in Kotlin so I only have elements which match t

Time:07-23

I have a class called Person

data class Person(
    val id: Int,
    val name: String
)

data class IDs(
    val id : Int,
    val active : Boolean )

and an array list that has numbers of ids and another list of Persons

val myStu = listOf<Person>(Person(1, "Name_1"), Person(2, "Name_2"), Person(3, "Name_3"))
var ids = listOf<IDs>(IDs(1,false),IDs(2,true),IDs(3,true))
var newIds = listOf<Int>(2,3,4,6)

First I want to apply two actions to the myStu, first is to have a list that include all the items from myStu that his id matches the id in the IDS and only if the active is true

myStu or the new list will have the values

Person(2, "Name_2"), Person(3, "Name_3"))

Then do action two , I need to add a new item to the new list that their id does not exist in the newIds , in another word we will add a new person Person(4,"None") and (6,"None) , 4 and 6 values come from newIds list

the final output will be :

   id= 2 name = "Name_2", id= 3 name = "Name_3", id= 4 name = "None" , id =6 name="None"

I want to write the code with filter , I failed with first step because I don't know how to use contains() with the list inside the filter

val newArr = myStu.filter {
    ids.contains(it.id)
}

CodePudding user response:

The "easiest" way of doing that would be to use filter directly, there's no need for contains. If we were to use contains, then we would need to also search for which element contained the id, in order to get the status. We can just do a .any() to do both at the same time.

V1

val activeStu = myStu.filter { person -> ids.any { it.id == person.id && it.active } }

val result = newIds.map { newId ->
    activeStu.find { it.id == newId } ?: Person(id = newId, name = "None")
}

Another method, that might work a bit better if we have big lists, would be to first transform the IDs list into a map. That way the second part of our code is a bit more efficient, since there is no search involved.

V2

val idsMap = ids.associate { it.id to it.active }
val activeStu = myStu.filter { idsMap[it.id] ?: false }

//the creation of the result list is the same

Version without creating 2 new lists. This works, but it might be quite ineficient processing wise, and also harder to understand what is going on IMO.

V3

val result = newIds.map { newId ->
    //try to find an IDs with the current newId and status as true
    when (ids.find { it.id == newId }?.active) {
        //if found, then find the corresponding Person  
        true -> myStu.find { it.id == newId } ?: Person(newId, "None") // if this happens, it means that an IDs with status true existed and no Person had that id. Not sure what you want in this scenario, this version creates one of the "none" persons.
        //if not found, then create a new one
        else -> Person(newId, "None")
    }
}

Note: depending on what version of kotlin you have, you might have to change the when statement to this:

when (ids.find { it.id == newId }?.active == true)

Since I think I remember that null didn't used to be treated as false in old versions (I've run this with version 1.4.20).

Btw, you can also use this version with the idsMap from V2, just replace the when(...) with when(idsMap[newId] or when(idsMap[newId] == true) depending on the kotlin version.

  • Related