Страницы

Поиск по вопросам

суббота, 28 декабря 2019 г.

Можно ли из одного Stream достать сразу и min() и max()?

#java #java_stream #max #java_9 #min


Пусть есть IntStream, возможно ли получить из него допустим массив или лист, в котором
будут 2 значения min и max стрима? Либо можно ли вообще каким-то образом вызвать терминальный
метод на стрим больше 1 раза?
    


Ответы

Ответ 1



IntSummaryStatistics stats = IntStream.range(1, 100) .summaryStatistics(); int min = stats.getMin(); int max = stats.getMax();

Ответ 2



Можно создать коллектор, находящий минимальный и максимальный элемент. Вообще рекомендую способ с IntSummaryStatistics, но коллектор можно сделать. Коллектор: static Collector> minMax( Comparator comparator, BiFunction finisher){ class Accumulator{ T min; T max; boolean present; void add(T value){ if(present){ if(comparator.compare(value, min) <0) min= value; if(comparator.compare(value, max) >0) max= value; }else { min=max=value; present=true; } } Accumulator combiner(Accumulator other){ if(!other.present) return this; if(!present) return other; if(comparator.compare(other.min, min) <0) min=other.min; if(comparator.compare(other.max, max) >0) max=other.max; return this; } } return Collector.of(Accumulator::new, Accumulator::add, Accumulator::combiner, accumulator -> accumulator.present ? Optional.of(finisher.apply(accumulator.min, accumulator.max)) : Optional.empty()); } Его использование может выглядит вот так: Integer [] arr= IntStream.of(12, 45, 23, 68). boxed(). collect( minMax( Integer::compareTo, (min, max) -> new Integer[] {min, max})).get(); for (Integer i: arr) { System.out.println(i); } Можно сделать чтоб возвращал List: List list =IntStream.of(12, 45, 23, 68). boxed(). collect( minMax( Integer::compareTo, (min, max) -> Arrays.asList(min, max))).get(); list.iterator().forEachRemaining(System.out::println);

Ответ 3



Нет, стрим позволяет пройтись по нему только один раз (а если нижележащий сплитератор выстрелит, то можно и вообще не дойти до конца). Но это не значит, что вы не можете одновременно собирать и максимум, и минимум: private static class Result { private Integer minimum; private Integer maximum; public Integer getMinimum() { return minimum; } public Integer getMaximum() { return maximum; } public synchronized Result update(int value) { if (minimum == null || minimum > value) { minimum = value; } if (maximum == null || maximum < value) { maximum = value; } return this; } public synchronized void combine(Result other) { if (other.getMinimum() != null) { update(other.getMinimum()); } if (other.getMaximum() != null) { update(other.getMaximum()); } } @Override public String toString() { return "Result {minimum=" + minimum + ", maximum=" + maximum + "}"; } } public static Result compute(IntStream stream) { return stream.collect(Result::new, Result::update, Result::combine); }

Ответ 4



Вот Ваш массив: int[] miniMax = IntStream.range(1, 11).collect(() -> { return new int[] { Integer.MAX_VALUE, Integer.MIN_VALUE }; }, (t, value) -> { if (t[0] > value) t[0] = value; if (t[1] < value) t[1] = value; }, (t, u) -> { if (t[0] > u[0]) t[0] = u[0]; if (t[1] < u[1]) t[1] = u[1]; }); int min = miniMax[0]; int max = miniMax[1]; Если попадётся пустой stream, то получится невероятный результат min == 2147483647 и max == -2147483648 Условие, что получено именно то, что надо: min <= max

Комментариев нет:

Отправить комментарий