Java 8 Streams: How to call once the Collection.stream() method and retrieve an array of several aggregate values with different fields -
i'm starting stream api in java 8.
here person object use:
public class person { private string firstname; private string lastname; private int age; private double height; private double weight; public person(string firstname, string lastname, int age, double height, double weight) { this.firstname = firstname; this.lastname = lastname; this.age = age; this.height = height; this.weight = weight; } public string getfirstname() { return firstname; } public string getlastname() { return lastname; } public int getage() { return age; } public double getheight() { return height; } public double getweight() { return weight; } } here code initializes list of objects person , gets number of objects filtered specific firstname, maximum age , minimum height, weight average, , create array of objects containing these values:
list<person> personslist = new arraylist<person>(); personslist.add(new person("john", "doe", 25, 1.80, 80)); personslist.add(new person("jane", "doe", 30, 1.69, 60)); personslist.add(new person("john", "smith", 35, 174, 70)); long count = personslist.stream().filter(p -> p.getfirstname().equals("john")).count(); int maxage = personslist.stream().maptoint(person::getage).max().getasint(); double minheight = personslist.stream().maptodouble(person::getheight).min().getasdouble(); double avgweight = personslist.stream().maptodouble(person::getweight).average().getasdouble(); object[] result = new object[] { count, maxage, minheight, avgweight }; system.out.println(arrays.tostring(result)); is possible single call stream() method , return array of objects directly ?
object[] result = personslist.stream()...count()...max()...min()...average() i asked similar question previously: java 8 streams: how call once collection.stream() method , retrieve array of several aggregate values time cannot use summarystatistics() method because use different fields (age, height, weight) retrieve aggregate values.
edit 2016-01-07
i tested solutions of tricore , tagir valeev, , computed running time each solution.
it seems tricore solution more efficient tagir valeev.
tagir valeev's solution seems not save time compared solution (using multiple streams).
here test class:
public class streamtest { public static class person { private string firstname; private string lastname; private int age; private double height; private double weight; public person(string firstname, string lastname, int age, double height, double weight) { this.firstname = firstname; this.lastname = lastname; this.age = age; this.height = height; this.weight = weight; } public string getfirstname() { return firstname; } public string getlastname() { return lastname; } public int getage() { return age; } public double getheight() { return height; } public double getweight() { return weight; } } public static abstract class process { public void run() { stopwatch timer = new stopwatch(); timer.start(); dorun(); timer.stop(); system.out.println(timer.gettime()); } protected abstract void dorun(); } public static void main(string[] args) { list<person> personslist = new arraylist<person>(); (int = 0; < 1000000; i++) { int age = random(15, 60); double height = random(1.50, 2.00); double weight = random(50.0, 100.0); personslist.add(new person(randomstring(10, mode.alpha), randomstring(10, mode.alpha), age, height, weight)); } personslist.add(new person("john", "doe", 25, 1.80, 80)); personslist.add(new person("jane", "doe", 30, 1.69, 60)); personslist.add(new person("john", "smith", 35, 174, 70)); personslist.add(new person("john", "t", 45, 179, 99)); // query mutiple streams new process() { protected void dorun() { queryjava8(personslist); } }.run(); // query 'tricore' method new process() { protected void dorun() { queryjava8_1(personslist); } }.run(); // query 'tagir valeev' method new process() { protected void dorun() { queryjava8_2(personslist); } }.run(); } // -------------------- // java 8 // -------------------- private static void queryjava8(list<person> personslist) { long count = personslist.stream().filter(p -> p.getfirstname().equals("john")).count(); int maxage = personslist.stream().maptoint(person::getage).max().getasint(); double minheight = personslist.stream().maptodouble(person::getheight).min().getasdouble(); double avgweight = personslist.stream().maptodouble(person::getweight).average().getasdouble(); object[] result = new object[] { count, maxage, minheight, avgweight }; system.out.println("java8: " + arrays.tostring(result)); } // -------------------- // java 8_1 - tricore // -------------------- private static void queryjava8_1(list<person> personslist) { object[] objects = personslist.stream().collect(collector.of(() -> new personstatistics(p -> p.getfirstname().equals("john")), personstatistics::accept, personstatistics::combine, personstatistics::tostatarray)); system.out.println("java8_1: " + arrays.tostring(objects)); } public static class personstatistics { private long firstnamecounter; private int maxage = integer.min_value; private double minheight = double.max_value; private double totalweight; private long total; private final predicate<person> firstnamefilter; public personstatistics(predicate<person> firstnamefilter) { objects.requirenonnull(firstnamefilter); this.firstnamefilter = firstnamefilter; } public void accept(person p) { if (this.firstnamefilter.test(p)) { firstnamecounter++; } this.maxage = math.max(p.getage(), maxage); this.minheight = math.min(p.getheight(), minheight); this.totalweight += p.getweight(); this.total++; } public personstatistics combine(personstatistics personstatistics) { this.firstnamecounter += personstatistics.firstnamecounter; this.maxage = math.max(personstatistics.maxage, maxage); this.minheight = math.min(personstatistics.minheight, minheight); this.totalweight += personstatistics.totalweight; this.total += personstatistics.total; return this; } public object[] tostatarray() { return new object[] { firstnamecounter, maxage, minheight, total == 0 ? 0 : totalweight / total }; } } // -------------------- // java 8_2 - tagir valeev // -------------------- private static void queryjava8_2(list<person> personslist) { // @formatter:off collector<person, ?, object[]> collector = multicollector( filtering(p -> p.getfirstname().equals("john"), collectors.counting()), collectors.collectingandthen(collectors.mapping(person::getage, collectors.maxby(comparator.naturalorder())), optional::get), collectors.collectingandthen(collectors.mapping(person::getheight, collectors.minby(comparator.naturalorder())), optional::get), collectors.averagingdouble(person::getweight) ); // @formatter:on object[] result = personslist.stream().collect(collector); system.out.println("java8_2: " + arrays.tostring(result)); } /** * returns collector combines results of supplied collectors * object[] array. */ @safevarargs public static <t> collector<t, ?, object[]> multicollector(collector<t, ?, ?>... collectors) { @suppresswarnings("unchecked") collector<t, object, object>[] cs = (collector<t, object, object>[]) collectors; // @formatter:off return collector.<t, object[], object[]> of( () -> stream.of(cs).map(c -> c.supplier().get()).toarray(), (acc, t) -> intstream.range(0, acc.length).foreach( idx -> cs[idx].accumulator().accept(acc[idx], t)), (acc1, acc2) -> intstream.range(0, acc1.length) .maptoobj(idx -> cs[idx].combiner().apply(acc1[idx], acc2[idx])).toarray(), acc -> intstream.range(0, acc.length) .maptoobj(idx -> cs[idx].finisher().apply(acc[idx])).toarray()); // @formatter:on } /** * filtering() collector (which added in jdk-9, see jdk-8144675) */ public static <t, a, r> collector<t, a, r> filtering(predicate<? super t> filter, collector<t, a, r> downstream) { biconsumer<a, t> accumulator = downstream.accumulator(); set<characteristics> characteristics = downstream.characteristics(); return collector.of(downstream.supplier(), (acc, t) -> { if (filter.test(t)) accumulator.accept(acc, t); } , downstream.combiner(), downstream.finisher(), characteristics.toarray(new collector.characteristics[characteristics.size()])); } // -------------------- // helper methods // -------------------- public static enum mode { alpha, alphanumeric, numeric } private static string randomstring(int length, mode mode) { stringbuffer buffer = new stringbuffer(); string characters = ""; switch (mode) { case alpha: characters = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; break; case alphanumeric: characters = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz1234567890"; break; case numeric: characters = "1234567890"; break; } int characterslength = characters.length(); (int = 0; < length; i++) { double index = math.random() * characterslength; buffer.append(characters.charat((int) index)); } return buffer.tostring(); } private static int random(int min, int max) { random rand = new random(); return rand.nextint((max - min) + 1) + min; } private static double random(double min, double max) { return min + math.random() * (max - min); } }
here collector
public class personstatistics { private long firstnamecounter; private int maxage = integer.min_value; private double minheight = double.max_value; private double totalweight; private long total; private final predicate<person> firstnamefilter; public personstatistics(predicate<person> firstnamefilter) { objects.requirenonnull(firstnamefilter); this.firstnamefilter = firstnamefilter; } public void accept(person p) { if (this.firstnamefilter.test(p)) { firstnamecounter++; } this.maxage = math.max(p.getage(), maxage); this.minheight = math.min(p.getheight(), minheight); this.totalweight += p.getweight(); this.total++; } public personstatistics combine(personstatistics personstatistics) { this.firstnamecounter += personstatistics.firstnamecounter; this.maxage = math.max(personstatistics.maxage, maxage); this.minheight = math.min(personstatistics.minheight, minheight); this.totalweight += personstatistics.totalweight; this.total += personstatistics.total; return this; } public object[] tostatarray() { return new object[]{firstnamecounter, maxage, minheight, total == 0 ? 0 : totalweight / total}; } } you can use collector follows
public class personmain { public static void main(string[] args) { list<person> personslist = new arraylist<>(); personslist.add(new person("john", "doe", 25, 180, 80)); personslist.add(new person("jane", "doe", 30, 169, 60)); personslist.add(new person("john", "smith", 35, 174, 70)); personslist.add(new person("john", "t", 45, 179, 99)); object[] objects = personslist.stream().collect(collector.of( () -> new personstatistics(p -> p.getfirstname().equals("john")), personstatistics::accept, personstatistics::combine, personstatistics::tostatarray)); system.out.println(arrays.tostring(objects)); } }
Comments
Post a Comment