I was wondering how to count different fields of an object using a single stream. I know I can easily count a single property of an object using streams (countedWithStream) or even using a for to count several at once (countedWithFor). But I would actually love to know if it would be possible to achieve the same as countedWithFor but using a single stream, generating the same output.
import com.google.common.collect.ImmutableMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.LongStream;
import static java.util.stream.Collectors.*;
class Scratch {
public static void main(String[] args) {
List<AnObject> objects = createObjects();
Map<String, Map<Long, Long>> countedWithStream = countUsingStream(objects);
Map<String, Map<Long, Long>> countedWithFor = countUsingFor(objects);
}
private static Map<String, Map<Long, Long>> countUsingStream(List<AnObject> objects) {
BiFunction<List<AnObject>, Function<AnObject, Long>, Map<Long, Long>> count = (ojs, mpr) -> ojs.stream()
.collect(groupingBy(mpr, counting()));
return ImmutableMap.<String, Map<Long, Long>>builder().put("firstId", count.apply(objects, AnObject::getFirstId))
.put("secondId", count.apply(objects, AnObject::getSecondId))
.build();
}
private static Map<String, Map<Long, Long>> countUsingFor(List<AnObject> objects) {
Map<Long, Long> firstIdMap = new HashMap<>();
Map<Long, Long> secondIdMap = new HashMap<>();
final BiFunction<Long, Map<Long, Long>, Long> count = (k, m) -> k != null ? m.containsKey(k) ? m.put(k, m.get(k) + 1L) : m.put(k, 1L) : null;
for (AnObject object : objects) {
count.apply(object.firstId, firstIdMap);
count.apply(object.secondId, secondIdMap);
}
return ImmutableMap.<String, Map<Long, Long>>builder().put("firstId", firstIdMap)
.put("secondId", secondIdMap)
.build();
}
private static List<AnObject> createObjects() {
return LongStream.range(1, 11)
.mapToObj(Scratch::createObject)
.collect(toList());
}
private static AnObject createObject(long id) {
return new AnObject(id, id);
}
private static class AnObject {
public final long firstId;
public final long secondId;
public AnObject(long firstId,
long secondId) {
this.firstId = firstId;
this.secondId = secondId;
}
public long getFirstId() {
return firstId;
}
public long getSecondId() {
return secondId;
}
}
countUsingStream) that you've shared. What is it that you're looking further for?