Java Streams v .Net (C#) LINQ



我需要知道一个字符串或字符数组是否有重复的字符,如果有的话,每个重复的字符有多少。

使用LINQ我可以这样做:-

class Program {
    private const string SOURCE = "appearances";
    static void Main(string[] args) {
        var testQ =
            from ch in SOURCE
            group ch by ch into testG
            where testG.Count<char>() > 1
            select testG;
        int num;
        foreach (var tg in testQ) {
            num = tg.Count();
            Console.Out.WriteLine("{0}, {1}", tg.ElementAt(0), num);
        }
        Console.ReadLine();
    }
}

谁能建议我如何使用Java流?

你说的Stream -我想你是指Java 8。

你可以这样做:

public Map<Character, Integer> countOccurs(final char[] input) {
    return countOccurs(new String(input));
}
public Map<Character, Integer> countOccurs(final String input) {
    return input.chars().
            collect(
                    HashMap::new,
                    (m, c) -> m.merge((char) c, 1, Integer::sum),
                    HashMap::putAll
            );
}

这个想法是我们取Stringchar值的IntStream作为int。然后我们将IntStream collect()转换成Map;这类似于函数式语言中的foldLeft操作。Map.merge方法接受一个键、一个值和一个lambda,如果一个值已经在Map中,则该lambda将现有值和新值合并——我们传递Integer::sum将这两个值加在一起。

intcharCharacter的体操是遗留Java问题。在新的Java 8 API中没有原语CharStream,所以我们必须使用IntStream -然后我们必须将int强制转换为char,然后它将被自动装箱为Character

使用例子:

System.out.println(countOccurs("abbccddde"));
输出:

{a=1, b=2, c=2, d=3, e=1}

如果您想要过滤计数,您可以简单地执行:

final Map<Character, Integer> count = countOccurs("abbccddde");
count.entrySet().stream().
    filter(e -> e.getValue() > 1).
    forEach(System.out::println);

这将给你:

b=2
c=2
d=3

如果你想在逻辑上类似于你的LINQ例子,那么这个工作:

public Collection<? extends Map.Entry<Character, Integer>> countOccurs(final String input) {
    return input.chars().boxed().
            collect(groupingBy(identity())).entrySet().stream().
            filter(e -> e.getValue().size() > 1).
            map(e -> new AbstractMap.SimpleEntry<>((char)(int)e.getKey(), e.getValue().size())).
            collect(toList());
}

但是它真的很难看,需要一个中间集合

注:请原谅格式,我还不确定如何格式化Stream操作的长行。我相信很快就会制定出样式指南。

最新更新