Home > Software engineering >  stream of objects containing multiple properties question
stream of objects containing multiple properties question

Time:06-11

I think I learning streams I have a huge case of brain fart...

I am trying to solve the following: given a list of objects, each object with multiple properties, like so:

    class Data{
        int prop1;
        int prop2;
    ...

List<Data> data;//list of Data object

i am trying, in a 'one shot' like operation, to stream the list, such that the end result will be an generic object or a data object where each prop get its own sum/max/min etc. so, for example, given 2 data objects as follows:

{1,2},{3,4} if I apply max to the first prop and sum to the second the result is {3,6}

thanks for helping!

CodePudding user response:

I am trying, in a 'one shot' like operation

You are looking for the Teeing Collector introduced in Java 12. Given a list of Data, where a Data class is something like:

@AllArgsConstructor
@Getter
@ToString
public class Data {
    int prop1;
    int prop2;
}

and a list:

List<Data> data = List.of(
    new Data(1,10),
    new Data(2,20),
    new Data(3,30),
    new Data(4,40)
);

the end result will be an generic object or a data object

if I apply max to the first prop and sum to the second

You can use Collectors.teeing to get a new Data object with the result of your operations

Data result =
data.stream().collect(Collectors.teeing(
        Collectors.reducing(BinaryOperator.maxBy(Comparator.comparing(Data::getProp1))),
        Collectors.summingInt(Data::getProp2),
        (optionalMax, sum) -> new Data(optionalMax.get().getProp1(), sum)
));

Or something else, for example a Map<String,Integer>

Map<String,Integer> myMap = 
data.stream().collect(Collectors.teeing(
        Collectors.reducing(BinaryOperator.maxBy(Comparator.comparing(Data::getProp1))),
        Collectors.summingInt(Data::getProp2),
        (optionalMax, sum) -> {
            HashMap<String, Integer> map = new HashMap();
            map.put("max_prop1", optionalMax.get().getProp1());
            map.put("sum_prop2", sum);
            return map;
        }
));

CodePudding user response:

It sounds like you're trying to retrieve some statistics from a stream of elements.

I am trying [...] to stream the list, such that the end result will be a generic object or a data object where each prop get its own sum/max/min etc.

For this purpose, there is already the IntSummaryStatistics class which includes a set of statistics gathered from a set of int elements. To obtain this information, you just need to stream your elements and invoke the collect operation by supplying Collectors.summarizingInt(); this will return the statistics of your elements. Moreover, Java also provides LongSummaryStatistics and DoubleSummaryStatistics to retrieve statistics of long and double types.

List<Integer> list = new ArrayList<>(List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
IntSummaryStatistics stats = list.stream()
        .collect(Collectors.summarizingInt(Integer::intValue));

System.out.println("Count: "   stats.getCount());
System.out.println("Sum: "   stats.getSum());
System.out.println("Min Value: "   stats.getMin());
System.out.println("Max Value: "   stats.getMax());
System.out.println("Average: "   stats.getAverage());

//In case Data had not been designed in place of IntSummaryStatistics and it's an actual needed class, 
//then you could set up the properties you need from the IntSummaryStatistics
Data d = new Data();
d.setMinProp(stats.getMin());
d.setMaxProp(stats.getMax());
d.setSumProp(stats.getSum());
//... setting any other needed property ...

Data class

class Data {
    private int minProp, maxProp, sumProp;

    //... rest of the implementation ...

    public void setMinProp(int minProp) {
        this.minProp = minProp;
    }

    public void setMaxProp(int maxProp) {
        this.maxProp = maxProp;
    }

    public void setSumProp(int sumProp) {
        this.sumProp = sumProp;
    }
}

Output

Count: 10
Sum: 45
Min Value: 0
Max Value: 9
Average: 4.5
  • Related