Как я могу получить последний элемент потока или списка в следующем коде?
Где data.careas
находится List<CArea>
:
CArea first = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal).findFirst().get();
CArea last = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal)
.collect(Collectors.toList()).; //how to?
Как видите, получить первый элемент filter
не сложно.
Однако получение последнего элемента в однострочнике - настоящая боль:
- Кажется, я не могу получить его напрямую от
Stream
. (Это имело бы смысл только для конечных потоков) - Также кажется, что вы не можете получить что-то вроде
first()
иlast()
изList
интерфейса, что действительно неприятно.
Я не вижу никаких аргументов для не обеспечивая first()
и last()
метод в List
интерфейсе, как элементы в наличии, упорядочены, и , кроме того размер известен.
Но согласно первоначальному ответу: как получить последний элемент конечного Stream
?
Лично мне это ближе всего:
int lastIndex = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal)
.mapToInt(c -> data.careas.indexOf(c)).max().getAsInt();
CArea last = data.careas.get(lastIndex);
Однако это подразумевает использование для indexOf
каждого элемента, что, скорее всего, вам обычно не нужно, поскольку это может снизить производительность.
java
list
java-8
java-stream
skiwi
источник
источник
Iterables.getLast
который использует Iterable, но оптимизирован для работыList
. Любимая мозоль в том, что этого нетgetFirst
.Stream
API вообще ужасно анальный, опуская множество удобных методов. LINQ C #, напротив, рад предоставить.Last()
и даже.Last(Func<T,Boolean> predicate)
, хотя он также поддерживает бесконечные перечисления.Stream
API нельзя полностью сопоставить с ним,LINQ
поскольку оба выполнены в совершенно другой парадигме. Это не хуже и не лучше, это просто другое. И определенно некоторые методы отсутствуют не потому, что разработчики оракула некомпетентны илиОтветы:
Получить последний элемент можно методом Stream :: reduce . Следующий листинг содержит минимальный пример для общего случая:
Эта реализация работает для всех упорядоченных потоков (включая потоки, созданные из списков ). Для неупорядоченных потоков по очевидным причинам не указано, какой элемент будет возвращен.
Реализация работает как для последовательных, так и для параллельных потоков . На первый взгляд это может показаться неожиданным, и, к сожалению, в документации об этом прямо не говорится. Однако это важная особенность потоков, и я пытаюсь ее прояснить:
(first, second) -> second
.Документация для тесно связанных сборщиков еще более ясна: «Чтобы гарантировать, что последовательное и параллельное выполнение дает эквивалентные результаты , функции сборщика должны удовлетворять ограничениям идентичности и ассоциативности ».
Вернемся к исходному вопросу: следующий код сохраняет ссылку на последний элемент переменной
last
и выдает исключение, если поток пуст. Сложность линейна по длине потока.источник
_
или аналогичный) в тех случаях, когда вам не нужен параметр? Так было бы:.reduce((_, current) -> current)
если бы только этот правильный синтаксис..reduce(($, current) -> current)
или.reduce((__, current) -> current)
(двойное подчеркивание).Stream.reduce(BinaryOperator<T>)
не упоминает,reduce
подчиняется ли порядок встреч, а операция терминала может игнорировать порядок встреч, даже если поток упорядочен. Кстати, слово «коммутативный» не появляется в javadocs Stream, поэтому его отсутствие мало что говорит нам.reduce((a,b)->b)
является ли правильное решение для получения последнего элемента (разумеется, в упорядоченном потоке) или нет. В заявлении Брайана Гетца говорится о том , что далее в документации API указано, чтоreduce("", String::concat)
это неэффективное, но правильное решение для конкатенации строк, которое подразумевает поддержание порядка встреч. Намерение хорошо известно, документация должна наверстать упущенное.Если у вас есть коллекция (или в более общем плане Iterable), вы можете использовать Google Guava
как удобный oneliner.
источник
Iterables.getLast(() -> data.careas.stream().filter(c -> c.bbox.orientationHorizontal).iterator())
Один лайнер (поток не нужен;):
источник
ArrayIndexOutOfBoundsException
.У Guava есть специальный метод для этого случая:
Это эквивалентно
stream.reduce((a, b) -> b)
но создатели утверждают, что у него намного лучшая производительность.Из документации :
Стоит отметить, что если поток неупорядочен, этот метод ведет себя как
findAny()
.источник
Если вам нужно получить последние N элементов. Можно использовать закрытие. Приведенный ниже код поддерживает внешнюю очередь фиксированного размера до тех пор, пока поток не достигнет конца.
Другой вариант - использовать операцию сокращения с использованием идентификатора в качестве очереди.
источник
Вы также можете использовать функцию skip (), как показано ниже ...
это очень просто в использовании.
источник
ArrayIndexOutOfBoundsException