JoelArmstrong
JoelArmstrong

Reputation: 81

How to check if an Array of strings is sorted in alphabetical order or not using Kotlin?

I am given a list of strings and I need to see if they are in alphabetical order.

I know I need to use a for loop and check the first character of each string but I don't know how to progress from there.

for (item in array)
     println(item[0])

For example ["adam", "ben", "chloe"] should return true.

And likewise for ["ben", "adam", "chloe"] should return false.

Upvotes: 8

Views: 7554

Answers (7)

Aivean
Aivean

Reputation: 10882

UPD: Since Kotlin 1.2 the following is available:

Most efficient variant, creates the smallest amount of intermediate objects:

listOf(1, 2, 3).asSequence().zipWithNext { a, b -> a <= b }.all { it }

Note on efficiency: Creates only two Sequence objects and one function object. Uses Boolean constants as an intermediate value. The final all invocation is inlined as a while loop over the sequence.


Slightly less efficient variant:

listOf(1, 2, 3).asSequence().windowed(2).all { (a, b) -> a <= b }

It's slightly less efficient, as it creates creates intermediate List(a, b) for every element of the original list.

Both of these variants were listed in the answers below by @Billbucket and @AshishChaudhary.


Old answer, for previous versions of Kotlin:

Here is a one liner:

val a = listOf("a", "b", "c")
a.zip(a.drop(1)).all { (a, b) -> a <= b }
// true

Explanation:

a.zip(a.drop(1)) returns pairs of neighbour elements. If in every pair first element is less or equal to the next, array is in order.

If you want to improve performance, you can wrap your array in lazy sequence first. In this case array won't be copied:

a.asSequence().let { it.zip(it.drop(1)).all { (a, b) -> a < b }  }

The whole thing is O(N) (single pass through array), which is optimal for this task.

Upvotes: 16

Kirill Groshkov
Kirill Groshkov

Reputation: 1761

In case you want to compare arbitrary Comparable list:

fun <T : Comparable<T>> isCollectionSortedAsc(list: Collection<T>): Boolean {
  return list.zipWithNext { a, b -> a.compareTo(b) == -1 }.all { it }
}

Based on the accepted answer above: https://stackoverflow.com/a/47296632/4919972

Upvotes: 1

Billbucket
Billbucket

Reputation: 175

you can use a simple one-liner:

array.zipWithNext { s1, s2 -> s1 <= s2 }.all { it }

Upvotes: 6

Ashish Chaudhary
Ashish Chaudhary

Reputation: 798

Another solution:

val list = listOf("a", "b", "c")
list.windowed(2).none { (a, b) -> a > b }
// true

Upvotes: 1

Ekeko
Ekeko

Reputation: 1981

A very simple and easy way to accomplish it is by sorting and comparing the original list with the sorted one (two lists are equal when they have the exact same elements in the same order). Since you mentioned you are dealing with an array, you first need to convert it to a list. This solution is not the best in terms of performance (it's O(n log n) and converts the array twice to a list) but it's very readable:

val test = array.asList() == array.asList().sorted()

The full code for your question could be:

println(if (array.asList() == array.asList().sorted()) "Strings are in alphabetical order." else "Strings are not in alphabetical order.")

Upvotes: 1

Julian Rubin
Julian Rubin

Reputation: 1235

Yet another solution :)

data class Result(val isInOrder: Boolean, val lastString: String) {
    val toString = when {
        isInOrder -> "Strings are in alphabetical order."
        else -> "Strings are not in alphabetical order."
    }
}

fun Array<String>.isInAlphabeticalOrder() =
    this.fold(Result(true, ""), { acc, word -> Result(acc.isInOrder && acc.lastString < word, word) })

fun main(args: Array<String>) {
    val test1 = arrayOf("adam", "ben", "chloe")
    val test2 = arrayOf("ben", "adam", "chloe")
    println(test1.isInAlphabeticalOrder().toString)
    println(test2.isInAlphabeticalOrder().toString)
}

Upvotes: 0

Sash Sinha
Sash Sinha

Reputation: 22360

Im sure you could do your desired task completely using a for-loop.

However in Kotlin I personally think it would be more idiomatic to do something like this using until:

fun isAlphabetical(stringsArray: Array<String>): Boolean {
    if (stringsArray.size < 2) return true
    return (1 until stringsArray.size).none { stringsArray[it] <= stringsArray[it - 1] }
}

fun main(args: Array<String>) {
    val testCases = arrayOf(arrayOf("adam", "ben", "chloe"), arrayOf("ben", "adam", "chloe"))

    for(testCase : Array<String> in testCases){
        println("The strings are: ${testCase.joinToString()}")
        if (isAlphabetical(testCase)) {
            println("Strings are in alphabetical order.\n")
        } else {
            println("Strings are not in alphabetical order.\n")        
        }
    }    
}

Output:

The strings are: adam, ben, chloe
Strings are in alphabetical order.

The strings are: ben, adam, chloe
Strings are not in alphabetical order.

Basically you only compare each element of the array with the previous element (using <=) if the length of the array is more than 1.

Upvotes: 1

Related Questions