关于函数式编程:Kotlin-字符串中的唯一字符

Kotlin - Unique Characters in String

我的函数应该返回一个布尔值,指示输入的String是否包含所有唯一字符。

例如
" abc"返回true," abca"返回false

1
2
3
4
fun uniqueCharacters(s: String): Boolean = s.groupBy { it }
    .values
    .stream()
    .allMatch { it.size == 1 }

是否有解决此问题的更有效方法?如果我以非功能方式解决此问题,则将所有字符存储到Map中,值是到目前为止该字符的计数,如果该值大于1,则中断并返回false。

不确定如何最好地将其转换为功能性的Kotlin代码。


您可以使用all函数和Set::add作为其谓词

1
2
3
4
5
6
fun main() {
    println("abc".allUnique()) // true
    println("abca".allUnique()) // false
}

fun String.allUnique(): Boolean = all(hashSetOf<Char>()::add)

这很懒,当找到第一个重复项时该函数将返回结果


也许最简单的方法是创建字符的Set,并检查其大小:

1
fun String.isUniqueCharacters() = toSet().size == length

(由于此函数仅取决于字符串的内容,因此使其成为扩展函数似乎是合乎逻辑的;这也使调用更容易。)

关于性能,它有效地创建了字符的哈希表,然后检查条目数(即唯一字符数)。所以这并不是小菜一碟,但我想不出一种更好的方法。

其他方法可能包括:

  • 将字符复制到数组,对其进行原位排序,然后将其扫描以比较相邻的元素。这样可以节省一些内存分配,但是需要更多处理。

  • 如上所述,但是使用手工编码的排序算法,该算法可发现重复项并尽早返回。在存在重复的情况下,这将减少处理,但是要付出更多编码的代价。 (当没有重复项时,手工编码的排序可能会比库排序慢。)

  • 创建一个由65536个布尔值组成的数组(每个可能的Char值*一个),所有数组都初始化为false,然后扫描字符串中的每个字符以检查对应的数组值(如果已经设置,则返回false,否则返回false)。进行设置)。那可能是最快的方法,但是会占用大量内存。 (而且初始化数组的成本可能很高。)

一如既往,这取决于权衡内存,处理和编码工作。

(** Unicode中的字符当然更多,但是Kotlin内部使用UTF-16,所以我们只需要65536。)


另一种方法

1
fun String.uniqueCharacters(): Boolean = this.toCharArray().distinct().isNotEmpty()