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

时间:2018-10-29 14:50:58

标签: java java-8 java-stream

我想确定列表是否使用anagram或Java 8。

示例输入:

"cat", "cta", "act", "atc", "tac", "tca"

我写了下面的函数来完成这项工作,但我想知道是否有更好,更优雅的方法来实现这一目标。

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;

}

似乎我无法使用Stream.sorted()方法对char数组进行排序,因此这就是我使用第二个map运算符的原因。如果有某种方法可以直接对char流而不是char数组的Stream进行操作,那也将有所帮助。

5 个答案:

答案 0 :(得分:10)

代替创建和排序char[]int[](无法内联完成并因此中断流),您可以获取{{1}中的Stream在字符串中进行排序,然后将其转换为数组。请注意,尽管这是一个chars,并且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; 代替四个map(s -> Arrays.toString(s.chars().sorted().toArray()))的序列。不确定速度是否有(显着)差异,这可能主要是口味问题。

此外,您可以使用maps来使数组具有可比性,这应该比IntBuffer.wrap快得多(这要感谢注释中的Holger)。

Arrays.toString

答案 1 :(得分:8)

我不会处理计数不同的值,因为那不是您感兴趣的。您想知道的是,根据特殊的相等性规则,所有元素是否相等。

因此,当我们创建将b转换为规范密钥(即所有字符已排序)的方法时

select a.column1, a.column2, 'a' as column3
from a
union all
select b.column1, b.column2, 'b' as column3
from b
where not exists (select 1 from a where a.column1 = b.column1);

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

String

请注意,对于格式为private CharBuffer canonical(String s) { char[] array = s.toCharArray(); Arrays.sort(array); return CharBuffer.wrap(array); } 的方法引用,该表达式只计算一次并捕获结果,因此对于整个流操作,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); } 仅计算一次,并且仅调用expression::name每个元素。

当然,您还可以使用Stream API创建规范密钥:

canonical(list[0])

equals方法不需要任何更改)

请注意,private IntBuffer canonical(String s) { return IntBuffer.wrap(s.chars().sorted().toArray()); } isAnagram可用作数组周围的轻量级包装器(如此答案),并根据实际数组适当地实现CharBufferIntBuffer内容。

答案 2 :(得分:4)

我不会对char数组进行排序,因为排序是EPSV,在这里没有必要。

对于列表中的每个单词,我们所需要做的就是计算每个字符的出现次数。为此,我们将每个单词的字符收集到const config = { ... debug: console.log, forcePasv: true, }; 中,其中键是每个字符,值是其计数。

然后,我们检查数组参数中所有单词的字符数是否相同,即映射是否相同:

O(NlogN)

答案 3 :(得分:2)

或者可以执行的实现的更新版本是:

boolean isAnagram(String[] list) {
    return Stream.of(list) // Stream<String>
            .map(String::toCharArray) // Stream<char[]>
            .peek(Arrays::sort) // sort 
            .map(String::valueOf) // Stream<String>
            .distinct() //distinct
            .count() == 1;
}

答案 4 :(得分:1)

或者可以与BitSet一起使用:

  System.out.println(stream.map(String::chars)
        .map(x -> {
            BitSet bitSet = new BitSet();
            x.forEach(bitSet::set);
            return bitSet;
        })
        .collect(Collector.of(
            BitSet::new,
            BitSet::xor,
            (left, right) -> {
                left.xor(right);
                return left;
            }
        ))
        .cardinality() == 0);