我有这样的任务:在排序的字符串流中,将3个相同字符串的所有组更改为一个包含大写字母的字符串(使用Java 8流API)。示例:
input = {"a","a","b","b","b","c"}
output = {"a","a","B","c"}
我可以在流中计算相同的字符串,但是我不理解如何在没有额外迭代的情况下替换组。我现在所拥有的是:
Map<String, Long> result = Stream.of("a","a","b","b","b","c")
.collect(Collectors.groupingBy(Function.identity(),
LinkedHashMap::new, Collectors.counting()));
System.out.println(result);
//当前输出:{a = 2,b = 3,c = 1}
答案 0 :(得分:0)
我可以在流中计数相同的字符串,但是我不知道如何 替换组,没有额外的迭代次数
如果您要坚持使用流方法,那么别无选择,只能流遍entrySet()
。
我要指出的第二件事是,与其使用counting
收集器,不如使用toList
收集器,这样会使流转时的生活更加轻松entrySet
执行进一步的操作。
即
Stream.of("a", "a", "b", "b", "b", "c")
.collect(groupingBy(Function.identity(),
LinkedHashMap::new,
toList()))
.entrySet().stream()
.flatMap(e -> e.getValue().size() == 3 ? Stream.of(e.getKey().toUpperCase()) :
e.getValue().stream())
.collect(toList());
出于完整性考虑,如果您要坚持使用counting
收集器,则可以执行以下操作:
Stream.of("a", "a", "b", "b", "b", "c")
.collect(groupingBy(Function.identity(),
LinkedHashMap::new,
counting()))
.entrySet().stream()
.flatMap(e -> e.getValue() == 3 ? Stream.of(e.getKey().toUpperCase()) :
Stream.generate(e::getKey).limit(e.getValue()))
.collect(Collectors.toList());
如果您想...也可以将Stream.generate(e::getKey).limit(e.getValue())
替换为LongStream.range(0, e.getValue()).mapToObj(s -> e.getKey())
。
答案 1 :(得分:0)
收集到一个列表,如果“看到一个三元组”,则快退。
List<String> coalesced = Stream.of("a", "a", "b", "b", "b", "c")
.sequential()
.collect(LinkedList::new, this::coalesce, List::addAll);
System.out.println(coalesced);
private void coalesce(LinkedList<String> list, String s) {
if (s.equals(list.peekLast()) &&
list.size() > 1 &&
s.equals(list.get(list.size() - 2))) {
list.removeLast();
list.removeLast();
list.add(s.toUpperCase());
} else {
list.add(s);
}
}
作为收集器,这是线程安全的,尽管以下内容仅对单线程流有效,直到List::addAll
被知道“三元组”可以跨越两个列表。