Sort array by alphabet using Kotlin

class CustomClass {
    var id: String = ""
    var name: String = ""
}

fun sortAlphabetically(arrayList: ArrayList< CustomClass >): ArrayList< CustomClass >{
        var returnList: ArrayList< CustomClass > = arrayListOf()
        var list = arrayList as MutableList< CustomClass >
        list.sortWith(Comparator { o1: CustomClass, o2: CustomClass ->
            o1.name.compareTo(o2.name)
        })
        returnList = list as ArrayList< CustomClass >
        return returnList
    }

The idiomatic way is to use the sortedBy extension method for List if you want to sort into a copy of the list. Or use sortBy extension on a MutableList if you want to sort in-place without a copy. An ArrayList would work as either list type.

// Sort a readonly list into a copy of the list

val appsList: List<AppInfo> = ...

val sortedAppsList = appsList.sortedBy { it.label?.toString() }

versus:

// Sort a mutable list in-place

val appsList: MutableList<AppInfo> = ...

appList.sortBy { it.label?.toString() }

and if holding as an ArrayList it is the same, but not idiomatic to have a reference directly to this concrete type.

// Sort an ArrayList list into a copy of the list

val appsList: ArrayList<AppInfo> = ...  // ALERT! not idiomatic

val sortedAppsList = appsList.sortedBy { it.label?.toString() }

// or if you want, feel free to sort in-place

appsList.sortBy { it.label?.toString() }

Note the toString() on the label: CharSequence member. You have to be careful sorting on a reference of type CharSequence as it is undefined what is its behavior for sorting (see: https://docs.oracle.com/javase/7/docs/api/java/lang/CharSequence.html)

This interface does not refine the general contracts of the equals and hashCode methods. The result of comparing two objects that implement CharSequence is therefore, in general, undefined.

If the CharSequence is already a String (likely is), then there is no harm in calling toString() as it just returns itself.

Also keep in mind that the nullable CharSequence has to be handled as well, and you need to decide where you want nulls: at the start or end of the list. I think the default is for them to go to the start.


Other notes about your code in the question:

Use the List or MutableList interface instead of the concrete class to reference the type, and use the methods from Kotlin stdlib to do actions upon the list. Also use val instead of var for references that will not change (meaning it will always point to the same list regardless of whether the list contents could change).

The big if statement you have can be reduced a lot, go from...

if(app.label?.toString()!!.length >= searchWord.length && app.label?.toString()!!.substring(0, searchWord.length) == searchWord.toUpperCase() && searchWord != "" ||
    app.label?.toString()!!.length >= searchWord.length && app.label?.toString()!!.substring(0, searchWord.length) == searchWord.toLowerCase() && searchWord != "" ||
    app.label?.toString()!!.length >= searchWord.length && app.label?.toString()!!.substring(0, searchWord.length) == searchWord.capitalize() && searchWord != "" ||
    app.label?.toString()!!.length >= searchWord.length && app.label?.toString()!!.substring(0, searchWord.length) == searchWord && searchWord != ""){

    if(app.packageName != "com.david.launcher" ){
        Appslist.add(app)
    }

}
if(searchWord == ""){
    if(app.packageName != "com.david.launcher"){
        Appslist.add(app)
    }
}

to simpler:

if (app.packageName != "com.david.launcher" &&
        (searchWord.isBlank() || 
         app.label?.startsWith(searchWord, ignoreCase = true) == true)) {
    appsList.add(app)
}

You should browse the standard library to get an idea of what is available so that you broaden your toolkit for the future.

Tags:

Kotlin