我需要知道一个字符串或字符数组是否有重复的字符,如果有的话,每个重复的字符有多少。
使用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
);
}
这个想法是我们取String
中char
值的IntStream
作为int
。然后我们将IntStream
collect()
转换成Map
;这类似于函数式语言中的foldLeft
操作。Map.merge
方法接受一个键、一个值和一个lambda,如果一个值已经在Map
中,则该lambda将现有值和新值合并——我们传递Integer::sum
将这两个值加在一起。
int
、char
和Character
的体操是遗留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
操作的长行。我相信很快就会制定出样式指南。