Add value after date is end in list kotlin

Viewed 136

hey I am working to create a list of type INCOMING, OUTGOING and TIME through enum class. My data class is populated through api call and filled according to that in the list. I want to modify to add TIME enum value whenever date ends the current one.

fun main() {
    val list = mutableListOf(
        Conversation(ConversationType.INCOMING.value, Sender(1, "2021/10/12")),
        Conversation(ConversationType.INCOMING.value, Sender(2, "2021/10/12")),
        Conversation(ConversationType.OUTGOING.value, Sender(3, "2021/10/11")),
        Conversation(ConversationType.OUTGOING.value, Sender(4, "2021/10/11")),
        Conversation(ConversationType.OUTGOING.value, Sender(5, "2021/10/11")),
        Conversation(ConversationType.OUTGOING.value, Sender(6, "2021/10/09")),
        Conversation(ConversationType.INCOMING.value, Sender(7, "2021/10/09")),
        Conversation(ConversationType.INCOMING.value, Sender(8, "2021/10/09")),
        Conversation(ConversationType.INCOMING.value, Sender(9, "2021/10/09")),
        Conversation(ConversationType.OUTGOING.value, Sender(10, "2021/10/08")),
        Conversation(ConversationType.OUTGOING.value, Sender(11, "2021/10/07"))
    )
}

Enum Class

enum class ConversationType(val value: Int) {
    INCOMING(1),
    TIME(0),
    OUTGOING(2);
}

data class Conversation(
    val type: Int? = null,
    val sender: Sender
)

data class Sender(
    val id: Int? = null,
    val date: String? = null
)

I need output like this

Conversation(type=1, sender=Sender(id=1, date=2021/10/12))
Conversation(type=1, sender=Sender(id=2, date=2021/10/12))
Conversation(type=0, sender=Sender(id=null, date=2021/10/12))
Conversation(type=2, sender=Sender(id=3, date=2021/10/11))
Conversation(type=2, sender=Sender(id=4, date=2021/10/11))
Conversation(type=2, sender=Sender(id=5, date=2021/10/11))
Conversation(type=0, sender=Sender(id=null, date=2021/10/11))
Conversation(type=2, sender=Sender(id=6, date=2021/10/09))
Conversation(type=1, sender=Sender(id=7, date=2021/10/09))
Conversation(type=1, sender=Sender(id=8, date=2021/10/09))
Conversation(type=1, sender=Sender(id=9, date=2021/10/09))
Conversation(type=0, sender=Sender(id=null, date=2021/10/09))
Conversation(type=2, sender=Sender(id=10, date=2021/10/08))
Conversation(type=0, sender=Sender(id=null, date=2021/10/08))
Conversation(type=2, sender=Sender(id=11, date=2021/10/07))
Conversation(type=0, sender=Sender(id=null, date=2021/10/07))
3 Answers

As I understand what you want, You need something like this:

var previousDate: String? = null
var i = -1
while (i < list.size) {
    i++
    val currentDate = list[i].date
    previousDate?.let {
        if (currentDate != previousDate) {
            list.add(i + 1, Conversation(ConversationType.TIME.value, Sender(null, it)))
        }
    }
    previousDate = currentDate
}

Other people already provided solutions based on manual iteration over indexes. Alternative that could be easier to read is to use mutable iterators. The resulting code is almost the same as your original attempt:

val iter = list.listIterator()
var previousDate = iter.next().sender?.date
iter.forEach { conversation ->
    val date = conversation.sender?.date
    if (date != previousDate) {
        iter.add(Conversation(...))
        previousDate = date
    }
}

With mutable iterators we can just add an item at the point where it is needed during iterating. We don't need to manage indexes manually.

This solution will throw an exception if the list is empty, so we should probably add a check for that case. You should also consider the case where sender or date is null. All solutions provided so far will behave odd in this case and you didn't specify what is your expected behavior.

Since you want to add items to the list while you're iterating it, you need to iterate the indices so you can insert items as you go. Since the list is growing as you go, you need to use a while loop instead of a for loop with the original indices.

var previousDate: String? = null
var i = 0
while (i < list.size) {
    val newDate = list[i].date
    if (newDate != previousDate && previousDate != null) {
        list.add(i++, Conversation(ConversationType.TIME.value, Sender(null, previousDate)))
    }
    previousDate = newDate
    i++
}

To explain my suggestion about simplifying using sealed interfaces, here is how I would redesign. I would replace your above classes with:

sealed interface Conversation {
    val date: String
}

sealed interface ConversationMessage: Conversation {
    val senderId: Int
}

data class IncomingConversation(
    override val date: String,
    override val senderId: Int
): ConversationMessage

data class OutgoingConversation(
    override val date: String,
    override val senderId: Int
): ConversationMessage

data class TimeStampConversation(override val date: String): Conversation

Then you don't have to worry about anything being null, you don't have to unpack enum values, and all the constructors are much easier to use. You can use when statements with is checks to determine which view holder to work with in your RecyclerView.

Related