Search code examples
kotlinkotlin-extension

Get index of given element from array extension function kotlin


I'd like to understand Kotlin extension functions more and am trying to implement an extension function for a List, to get the index of an element by passing the value of the position (if that makes sense).

What I have:

fun List<String>.getItemPositionByName(item: String): Int {
    this.forEachIndexed { index, it ->
        if (it == item)
            return index
    }
    return 0
}

Although this works fine, I would need the same thing for Int too. To my question, is there a way of combining this into one extension function instead of two seperate ones? I acknowledge that this isn't a lot of code and wouldn't hurt to be duplicated but out of interest and for future references.

I'm aware of this question Extension functions for generic classes in Kotlin where the response is - as I understand it at least - "doesn't quite work like this, but I don't really need it for type but "just" for String and Int.


Solution

  • Kotlin supports what C++ people would refer to as specialization to a certain degree. It works just fine for very basic types like you're using so what you're asking of is definitely possible.

    We can declare the following declarations. Of course you could just duplicate the code and you'd be on your way.

    public fun List<String>.getItemPositionByName(item: String) = ...
    public fun List<Int>.getItemPositionByName(item: String) = ...
    

    If you're not a fan of repeating the code, the idiomatic way would be to make use of file-private functions and simply delegating to the private function.

    private fun <T> getItemImpl(list: List<T>, item: T): Int {
        list.forEachIndexed { index, it ->
            if (it == item)
                return index
        }
        return -1
    }
    
    public fun List<String>.getItemPositionByName(item: String) = getItemImpl(this, item)
    public fun List<Int>.getItemPositionByName(item: Int) = getItemImpl(this, item)
    

    This limits the getItemImpl which is fully generic to the current file you're in while the Int and String specializations are publicly available anywhere else.

    Attempting to call getItemPositionByName on any list which is not of type List<Int> or List<String> will fail with a type error.

    Kotlin Playground Link: https://pl.kotl.in/NvIRXwmpU

    And just in case you weren't aware, the method you're implementing already exists in the standard library (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/index-of.html)