确定是否由Java 8中的anagram元素组成的列表

Lim*_*ufu 11 java java-8 java-stream

我想确定列表是否是使用Java 8的字谜.

输入示例:

"cat", "cta", "act", "atc", "tac", "tca"
Run Code Online (Sandbox Code Playgroud)

我已经编写了以下功能来完成这项工作,但我想知道是否有更好,更优雅的方法来做到这一点.

boolean isAnagram(String[] list) {
    long count = Stream.of(list)
            .map(String::toCharArray)
            .map(arr -> {
                Arrays.sort(arr);
                return arr;
            })
            .map(String::valueOf)
            .distinct()
            .count();
    return count == 1;

}
Run Code Online (Sandbox Code Playgroud)

看来我不能用Stream.sorted()方法对char数组进行排序,这就是我使用第二个map运算符的原因.如果有一些方法可以直接在char流而不是Stream of char数组上运行,那也会有所帮助.

tob*_*s_k 10

而不是创建和分选的char[]还是int[],这是不能被内联,从而实现"突破"流,你可以得到Streamchars在字符串并将其转换为数组排序之前那些.请注意,这是一个IntSteam,并且String.valueOf(int[])将包括数组的内存地址,这在这里不是很有用,所以Arrays.toString在这种情况下更好用.

boolean anagrams = Stream.of(words)
        .map(String::chars).map(IntStream::sorted)
        .map(IntStream::toArray).map(Arrays::toString)
        .distinct().count() == 1;
Run Code Online (Sandbox Code Playgroud)

当然,你也可以使用map(s -> Arrays.toString(s.chars().sorted().toArray()))而不是四个系列maps.不确定速度是否存在(显着)差异,这可能主要是品味问题.

此外,您可以使用IntBuffer.wrap使阵列具有可比性,这应该比Arrays.toString(在评论中感谢Holger)快得多.

boolean anagrams = Stream.of(words)
        .map(s -> IntBuffer.wrap(s.chars().sorted().toArray()))
        .distinct().count() == 1;
Run Code Online (Sandbox Code Playgroud)

  • @Michael你在包装数组时可以免费获得它,`charBuffer.wrap(array)`用于`char []`,`intBuffer.wrap(array)`用于`int []`.无需昂贵的转换为`String` ...... (2认同)

Hol*_*ger 8

我不打算计算不同的值,因为那不是你感兴趣的.你想知道的是,根据特殊的平等规则,所有元素是否相等.

所以当我们创建一个方法来转换String为规范键(即所有字符排序)

private CharBuffer canonical(String s) {
    char[] array = s.toCharArray();
    Arrays.sort(array);
    return CharBuffer.wrap(array);
}
Run Code Online (Sandbox Code Playgroud)

我们可以简单地检查所有后续元素是否等于第一个元素:

boolean isAnagram(String[] list) {
    if(list.length == 0) return false;
    return Arrays.stream(list, 1, list.length)
        .map(this::canonical)
        .allMatch(canonical(list[0])::equals);
}
Run Code Online (Sandbox Code Playgroud)

请注意,对于表单的方法引用expression::name,表达式计算一次并捕获结果,因此canonical(list[0])仅对整个流操作计算一次,并且仅equals针对每个元素调用.

当然,您也可以使用Stream API创建规范键:

private IntBuffer canonical(String s) {
    return IntBuffer.wrap(s.chars().sorted().toArray());
}
Run Code Online (Sandbox Code Playgroud)

(该isAnagram方法不需要任何改变)

需要注意的是CharBuffer,并IntBuffer可以在这个答案可以为使用轻量级的包装器阵列等,实施equalshashCode适当的,根据实际的数组内容.