Reputation: 780
My function should return a boolean indicating whether the input String contains all unique characters.
e.g. "abc" returns true, "abca" returns false
fun uniqueCharacters(s: String): Boolean = s.groupBy { it }
.values
.stream()
.allMatch { it.size == 1 }
Is there a more efficient way of solving this problem? If I was solving this in non-functional way I would store all the characters in a Map with the value being the count of that character so far, if it is greater than one then break and return false.
Not sure how best to translate this into a functional Kotlin piece of code.
Upvotes: 2
Views: 4485
Reputation: 4701
Yet another approach
fun String.uniqueCharacters(): Boolean = this.toCharArray().distinct().isNotEmpty()
Upvotes: 2
Reputation: 9672
You can use all
function and Set::add
as predicate for it
fun main() {
println("abc".allUnique()) // true
println("abca".allUnique()) // false
}
fun String.allUnique(): Boolean = all(hashSetOf<Char>()::add)
It's lazy, the function returns the result when it finds the first duplicate
Upvotes: 12
Reputation: 18537
Perhaps the simplest way is to create a Set
of the characters, and check its size:
fun String.isUniqueCharacters() = toSet().size == length
(Since this function depends only on the contents of the string, it seems logical to make it an extension function; that makes it easier to call, too.)
As for performance, it's effectively creating a hash table of the characters, and then checking number of entries, which is the number of unique characters. So that's not trivial. But I can't think of a way which is significantly better.
Other approaches might include:
Copying the characters to an array, sorting it in-place, and then scanning it comparing adjacent elements. That would save some memory allocation, but needs more processing.
As above, but using a hand-coded sort algorithm that spots duplicates and returns early. That would reduce the processing in cases where there are duplicates, but at the cost of much more coding. (And the hand-coded sort would probably be slower than a library sort when there aren't duplicates.)
Creating an array of 65536 booleans (one for every possible Char
value*), all initialised to false, and then scanning through each character in the string checking the corresponding array value (returning false if it was already set, else setting it). That would probably be the fastest approach, but takes a lot of memory. (And the cost of initialising the array could be significant.)
As always, it comes down to trading off memory, processing, and coding effort.
(* There are of course many more characters than this in Unicode, but Kotlin uses UTF-16 internally, so 65536 is all we need.)
Upvotes: 5