Возвратить средние значения из списка <T>как один объект T - PullRequest
0 голосов
/ 20 сентября 2019

Мне было интересно, есть ли способ использовать поток, чтобы получить один T объект из List<T> со средними значениями для двойных значений и минимальными значениями для даты.У меня около 20 объектов, и, может быть, есть способ пройти все из них автоматически, и если свойство равно двойному, чтобы получить среднее значение, если есть дата, чтобы получить минимум?

id     date                     value
3470,  2018-11-15 08:10:00+02,  25,101610.0234375
3467,  2018-11-15 07:53:00+02,  33,101398.984375
3468,  2018-11-15 07:54:00+02,  25,101599.765625
3549,  2018-12-28 18:20:00+02,  29.21
3550,  2018-12-28 18:24:00+02,  29.21
3551,  2018-12-28 18:27:00+02,  42.21
3552,  2019-01-07 09:42:00+02,
3553,  2019-01-07 09:50:00+02,  15.140000343323
3554,  2019-01-07 09:52:00+02,  -1.3799999952316
3555,  2019-01-07 10:03:00+02,  14.949999809265

Ответы [ 3 ]

2 голосов
/ 20 сентября 2019

Из вашего описания единственное, что всплывает в моей голове - это отражение.

Вы также можете определить нижестоящую функцию:

BinaryOperator<T> downstream = (t1, t2) -> new T(t1.getValue() + t2.getValue(), ..., t1.getDate().isBefore(t2.getDate()) ? t1.getDate() : t2.getDate());

И затем уменьшить:

T aggregate = list.stream().reduce(downstream).get();
T result = new T(aggregate.getValue() / list.size(), aggregate.getDate(), ...)

PS1: обратите внимание, что это создает дополнительные издержки, так как создает новый объект в BinaryOperator, поэтому это может быть не лучшим решением, когда список большой.

PS2: Это черновик,Я предположил, что вы используете LocalDateTime для хранения date поля, это зависит от того, что вы используете.

PS3: вам нужно определить метод агрегирования для ваших полей, например id.

PS4: Как заметил @Aaron - я вычисляю сумму для поля value, чтобы затем разделить ее на длину результата, чтобы среднее значение было правильно рассчитано.

1 голос
/ 20 сентября 2019

взгляните на сборщик тире , который был представлен в Java 12. В худшем случае вы можете скопировать / вставить реализацию (как это было сделано здесь )

Result result = stream.collect(Collectors.teeing(
            Collectors.mapping(T::getDate, Collectors.minBy(Comparator.naturalOrder())),
            Collectors.averagingDouble(T::getValue),
            Result::new
    ));

где result - это определенный вами класс

class Result {
    Optional<LocalDate> minDate;
    double avg;
    //all args constructor
}
0 голосов
/ 20 сентября 2019

Я думаю, что наиболее эффективным и чистым решением является использование метода Stream::reduce и определение функции сокращения клиента, которая выполняет min для определенных полей и average для других полей в зависимости от того, что вам нужно.

list.stream().reduce(initialValue, (accumulator, listElement) -> reduceFunction(accumulator, listElement))

Здесь есть небольшая трудность в том, что вам нужно знать длину списка, чтобы вычислить среднее значение.Таким образом, чтобы функция Reduce была универсальной, класс аккумулятора должен иметь счетчик элементов.

...