Elimizde şöyle bir kod olsun
// Bir değer nesnesirecord FieldValue(long value){}// Bir işlem tipirecord Aggregator(long id, Type type)public enum Type {SUM, AVG, MAX, MIN;}}// Bir işlem ve ona uygulanacak değerMap<Aggregator, FieldValue> values = Map.of(new Aggregator(1L, Type.AVG), new FieldValue(10L),new Aggregator(2L, Type.AVG), new FieldValue(20L),new Aggregator(3L, Type.SUM), new FieldValue(30L),new Aggregator(4L, Type.SUM), new FieldValue(40L),new Aggregator(5L, Type.MAX), new FieldValue(50L),new Aggregator(6L, Type.MAX), new FieldValue(60L),new Aggregator(7L, Type.MIN), new FieldValue(70L),new Aggregator(8L, Type.MIN), new FieldValue(80L));
Normalde groupBy ile işlem tipine göre gruplama yapmak çok kolay. Ama burada işlem tipine göre değer nesnesini bir metoda geçmek istiyoruz. Şöyle yaparız
Map<Aggregator.Type, Double> result = aggregate(values); public Map<AggregatorType, Double> aggregate(Map<A, B> fields) { // Aynı işlem tipine göre değerleri grupla Map<AggregatorType, List<Long>> valuesByType = fields.entrySet() .stream() .collect(Collectors.groupingBy( entry -> entry.getKey().type(), Collectors.mapping( entry -> entry.getValue().value(), Collectors.toList()) )); // Her işlem tipine göre listeyi hesapla return valuesByType.entrySet() .stream() .collect(Collectors.toMap( entry -> entry.getKey(), entry -> collectValues(entry.getKey(), entry.getValue()) )); } private double collectValues(AggregatorType aggregator, List<Long> values) { DoubleStream stream = values.stream().mapToDouble(x -> x + 0.0d); return switch (aggregator) { case AVG -> stream.average().orElseThrow(); case SUM -> stream.sum(); case MAX -> stream.max().orElseThrow(); case MIN -> stream.min().orElseThrow(); default -> throw new IllegalArgumentException(); }; }
Ama burada switch ile işlem tipine bakmak gerekiyor. Biraz daha Polymorphism için bunu görevi Type Enum'una taşıyabiliriz. Şöyle yaparız
@RequiredArgsConstructor public enum Type { SUM(values -> doubleStream(values).sum()), AVG(values -> doubleStream(values).average().orElseThrow()), MAX(values -> doubleStream(values).max().orElseThrow()), MIN(values -> doubleStream(values).min().orElseThrow()); private final Function<List<Long>, Double> aggregator; public Double aggregate(List<Long> values) { return aggregator.apply(values); } private static DoubleStream doubleStream(List<Long> values) { return values.stream().mapToDouble(v -> v + 0.0d); } }
Bu durumda aggregate metodu şöyle olur
public Map<Aggregator.Type, Double> aggregate(Map<Aggregator, FieldValue> fields) { // Aynı işlem tipine göre değerleri gruplaa Map<Aggregator.Type, List<Long>> valuesByType = ... return valuesByType.entrySet() .stream() .collect(Collectors.toMap( entry.getKey(), entry.getKey().aggregate(entry.getValue()) // Switch yerine Type nesnesini kullan )); }
Hiç yorum yok:
Yorum Gönder