1

I have these code segments. I want to find the optimal solution and if it's possible some explanation why my 1st piece of code is broken. I have struggled with adding elements to the existing Array<>, without minimal external stuff. I tried with +=' '.plus(), and.plusElement(), and the only solution I found to work is by coping the current array to MutableList and then adding an element to it. After that, I convert it again to Array and return the right type Array<>. I am sure that there is a more elegant way, but I can't brainstorm it.

Question 2: I also tried to shorten the code with with(), let{} run{}, etc. to make program.description.data.options as it. or this. instead of creation of new var clone

Thank you in advance :)

I have some nested data classes for Serialization in Kotlin

*FavouriteProgramCommandString have property val description: FavouriteProgram

-> FavouriteProgram have val data: FavouriteProgramDetails

-> FavouriteProgramDetails have var options: Array<FavouriteProgramOptions>, *

data class FavouriteProgramDetails(
   @SerializedName(value = "key", alternate = ["featureKey"])
   val key: String,
   @SerializedName("options")
   var options: Array<FavouriteProgramOptions>,
)

Broken code:

    @JvmStatic
    fun getProgramDescriptionOfFavouritesWithDelayOption(
        program: FavouriteProgramCommandString,
        key: String,
        delayDuration: Double = 0.0,
    ): FavouriteProgram {

        with(program.description.data.options) {

            val nodeOption =
                firstOrNull { it.key == key }

            if (nodeOption != null) {
                this[this.indexOf(nodeOption)].value = delayDuration
            } else {
                this.plus(FavouriteProgramOptions(key, delayDuration)) // DONT'WORK
            }
        }
        return program.description // Absolutly the same array is returned.
    }

Working code:

    @JvmStatic
    fun getProgramDescriptionOfFavouritesWithDelayOptio2n(
        program: FavouriteProgramCommandString,
        key: String,
        delayDuration: Double = 0.0,
    ): FavouriteProgram {
        val clone = program.description.data.options.toMutableList()

        val nodeOption =
            clone.firstOrNull { it.key == key }

        if (nodeOption != null) {
            val index = clone.indexOf(nodeOption)
            clone[index].value = delayDuration
        } else {
            clone.add(FavouriteProgramOptions(key, delayDuration)) // It's working.
        }
        program.description.data.options = clone.toTypedArray() 

        return program.description // Return what is expected.
    }
4
  • 3
    Is there any reason as to why the property is an Array and not a List (or mutable list)? The whole purpose of an array is that it is a fixed size sequential memory region. Your FavouriteProgramOptions object is obviously not a primitive as well, so there isn't even that optimisation to gain. Commented Jul 8, 2022 at 16:31
  • 1
    plus() is an operator function that appends the element to a NEW collection, and returns the result. It does NOT change the initial list provided. kotlinlang.org/docs/collection-plus-minus.html Commented Jul 9, 2022 at 3:02
  • @Alex.T yes, because code basis is made of Array ( it's a heritage from previous devs, I asked myself the same question) These classes are used in a lot of places in an app, and I should change tons of linked functions params from Array to MutableList. (this can create bugs and stuff ) :/ Also one part of the project is with Java other with Kotlin. Thank you :) Commented Jul 11, 2022 at 11:45
  • @aSemy yes I checked that later , thanks :) Commented Jul 11, 2022 at 11:50

1 Answer 1

1

Elements cannot be added to or removed from an array. What you can do is create new arrays, with new elements, and this is what methods like toTypedArray and plus do. You need to assign this newly created array back to program.description.data.options, like you did in your working attempt:

program.description.data.options = clone.toTypedArray() 
                                ^^^
                       you assigned it here

Scope functions won't help you if you don't assign the newly created array!

program.description.data.options = with(program.description.data.options) {
    val nodeIndex = indexOfFirst { it.key == key }

    if (nodeIndex != -1) {
        this.also { this[nodeIndex].value = delayDuration }
    } else {
        this + FavouriteProgramOptions(key, delayDuration)
    }
}

Notice the assignment at the very beginning. with returns either this, with some changes, or a copy of this, but with one new element added. I've replaced plus with the operator form, which is more idiomatic, and avoided going through the array twice by using indexOfFirst.

In my opinion, it would be better for program.description.data.options to be a MutableMap instead. Then it would be easier to do this kind of operation. It'd be a simple getOrPut:

program.description.data.options.getOrPut(key) { FavouriteProgramOptions(key, delayDuration) }.value = delayDuration

Even using a MutableList instead would avoid making copies of the entire array each time you do this.

Sign up to request clarification or add additional context in comments.

Comments

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.