https://kotlinlang.org logo
Title
v

Vivek Modi

06/01/2022, 2:19 PM
Hey I have object of
Event
. I want to combine all property value into single string. I did this without any problem. I want to know is there any better way to optimise this code in memory, efficiency etc. SingleEventString.kt
fun main() {
        var newString: String? = null
        val eventList = createData()
        eventList.forEachIndexed { index, event ->
            val title = event.title
            val status = event.status
            if (!title.isNullOrEmpty()) {
                newString = if(index == 0){
                    "$title"
                }else{
                    "$newString $title"
                }
            }
            if (!status.isNullOrEmpty()) {
                newString = "$newString $status"
            }
        }
        println(newString)
    }
    
    data class Event(val title: String? = null, val status: String? = null)
    
    fun createData() = listOf(
        Event("text 1", "abc"),
        Event("text 2", "abc"),
        Event("text 3", "abc"),
        Event("text 4", "abc"),
        Event("", "abc"),
        Event(null, "abc")
)
s

Sam

06/01/2022, 2:27 PM
You could use a StringBuilder for this (either on its own or via buildString)
l

Luke

06/01/2022, 2:31 PM
To add to that, you could use
eventList.fold(StringBuilder()) { builder, event -> ... }.toString()
v

Vivek Modi

06/01/2022, 2:33 PM
what is builder and event?
l

Luke

06/01/2022, 2:36 PM
builder would be the StringBuilder, and event would be each event one after the other. But I am just realizing that what you want is even simpler:
eventList.joinToString(separator = " ") { event -> ... }
. This maps each event to a string and concats them with a space separator
:nice: 3
v

Vivek Modi

06/01/2022, 2:38 PM
That's great. I'll try on my side
@Luke I tried this code
fun main() {
    var newString: String? = null
    val eventList = createData()
    eventList.joinToString(separator = " ") { event ->
        val title = event.title
        val status = event.status
        if (!title.isNullOrEmpty()) {
            newString = "$newString $title"
        }
        if (!status.isNullOrEmpty()) {
            newString = "$newString $status"
        }
        newString.toString()
    }
    println(newString)
}
and getting this
null text 1 abc text 2 abc text 3 abc text 4 abc abc abc
How to remove null in this ?
l

Luke

06/01/2022, 2:55 PM
val newString = eventList.joinToString(separator = " ") { event ->
    when {
        title.isNullOrEmpty() -> status.orEmpty()
        status.isNullOrEmpty() -> title
        else -> "$title $status"
    }
}
v

Vivek Modi

06/01/2022, 3:00 PM
Sorry can you please explain me what is going on this 1.
event.title.isNullOrEmpty() ->  event.status.orEmpty()
2.
event.status.isNullOrEmpty() -> event.title
why 1st one have
orEmpty()
and 2nd don't ?
@Luke 👆
l

Luke

06/01/2022, 3:05 PM
1. If the title is null or is the empty string, you return the status. If the status is null, you return the empty string 2. Since we already checked that the title is neither null or empty, then calling orEmpty here is redundant
Another solution, which you might find easier to understand (?), is this:
val newString = createData().asSequence()
    .flatMap { sequenceOf(it.title, it.status) }
    .filterNotNull()
    .filterNot { it.isEmpty() }
    .joinToString(separator = " ")
🙌 2
Basically, create an iteration of every title and status, filter out nulls and empty strings, and concatenate with space separator
v

Vivek Modi

06/01/2022, 3:11 PM
Ok now this is great example. I can easily understand that one. Thanks a million
And above solution is working fine
n

nkiesel

06/01/2022, 5:21 PM
you cold also replace
.filterNotNull().filterNot { it.isEmpty() }
with
.filterNot { it.isNullorEmpty() }
1
v

Vivek Modi

06/01/2022, 5:22 PM
Sure thanks
e

ephemient

06/01/2022, 9:47 PM
createData().flatMap {
    listOfNotNull(
        it.title?.ifEmpty { null },
        it.status?.ifEmpty { null },
    }
}.joinToString(separator = " ")
v

Vivek Modi

06/02/2022, 8:42 AM
@ephemient thank you so much. Can you please explain me what is difference between
flatMap
and
Map
? Thanks
e

ephemient

06/02/2022, 9:29 AM
.flatMap { … }
behaves like
.map { … }.flatten()
n

nkiesel

06/02/2022, 9:38 AM
listOfNotNull returns a list (containing 0, 1, or 2 elements in your concrete example) for every item returned from createData. Therefore, a .map would return a list of these lists. flatMap (as just explained) flattens this to a simple list by concatenating all the inner lists.
listOf(Data("t1", null), Data(null, "s2"), Data("t3", "s3")).map { listOfNotNull( it.title?.ifEmpty { null }, it.status?.ifEmpty { null }) } // [[t1], [s2], [t3, s3]]
listOf(Data("t1", null), Data(null, "s2"), Data("t3", "s3")).flatMap { listOfNotNull( it.title?.ifEmpty { null }, it.status?.ifEmpty { null }) } // [t1, s2, t3, s3]
v

Vivek Modi

06/02/2022, 9:50 AM
great explanation. Thank you so much guys. @nkiesel @ephemient