Search code examples
listkotlinreturnsize

Is there an efficient alternative (in Kotlin) to this code format: <functionReturningAList>().size?


If the function will execute first before getting the size, then I think that it will be inefficient because you're just getting the size of the returning list, the number of elements of which is immutable anyways (I mean list doesn't allow element addition, so the size of the returning list is supposed to be constant).

For context, I want to hold a reference to the size of the returned list, as a qualification in a later if condition, such that if I ever programmatically change the number of list elements, I don't need to also manually change the 'qualified' size, it as a constant.

I'm worried that if I apply the above format to codes, it will become a bad practice, a concise code sacrificing performance.

For example:

class Sampler {
        // notice this is var
        var sampleList = initializeList()
        
        // ...

        companion object {
            private fun initializeList(): List<Int> =
                listOf(
                    // these functions may return differently later
                    anObject.getNumber(1),
                    anotherObject.getInt(2),
                    yetAnotherObject.getInteger(3)
                    // can be programmatically added later
                )

            fun sampleMethod(numberToBeCompared) {
                // I don't want to do this: numberToBeCompared == QUALIFIED_LIST_CONSTANT
                if (numberToBeCompared == initializeList().size)
                    println("do something")

                // ...

            }
        }
    }

Solution

  • How about storing a List<() -> Int>? That is, turn each of the expressions for the elements in the list to a "thunk", that when invoked, returns the element:

    val listOfThunks =
        listOf(
            { anObject.getNumber(1) },
            { anotherObject.getInt(2) },
            { yetAnotherObject.getInteger(3) }
            // can be programmatically added later
        )
    

    Since this is just a bunch of lambda expressions, it can be evaluated very quickly.

    Then initializeList can be implemented as mapping each element to its invoked result:

    private fun initializeList(): List<Int> = listOfThunks.map { it() }
    

    To get the size, simply get listOfThunks.size, which does not invoke any of the lambdas, nor initializeList.