다음 코드에서 스트림 또는 목록의 마지막 요소를 어떻게 얻을 수 있습니까?
어디 data.careas
A는 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
모든 요소에를 사용하는 것이 포함되며 성능을 저하시킬 수 있으므로 일반적으로 원하지 않을 가능성이 큽니다.
답변
Stream :: reduce 메서드를 사용하여 마지막 요소를 가져올 수 있습니다 . 다음 목록에는 일반적인 경우에 대한 최소한의 예가 포함되어 있습니다.
Stream<T> stream = ...; // sequential or parallel stream
Optional<T> last = stream.reduce((first, second) -> second);
이 구현은 정렬 된 모든 스트림 ( Lists 에서 생성 된 스트림 포함)에 대해 작동합니다 . 주문 되지 않은 경우 스트림이 요소가 반환됩니다 지정되지 않은 분명한 이유입니다.
구현은 순차 및 병렬 스트림 모두에서 작동 합니다 . 언뜻보기에는 놀랍고 불행히도 문서에 명시 적으로 명시되어 있지 않습니다. 그러나 이것은 스트림의 중요한 기능이며 명확히하려고합니다.
- 방법에 대한 자바 독 스트림 :: 감소 가 있는지, 상태 “입니다 하지 실행하는 데 제약이 순차적으로 “ .
- Javadoc은 또한 “누산기 함수가 두 값을 결합하기위한 연관성 , 비 간섭 성 , 상태 비 저장 함수 여야 함”을 요구합니다. 이는 분명히 람다 표현식의 경우입니다.
(first, second) -> second
. - 축소 작업을 위한 Javadoc은 다음과 같이 설명합니다. “스트림 클래스에는 reduce () 및 collect () [..] 라고하는 여러 형태의 일반 축소 작업이 있습니다 .” 및 “적절하게 구성된 축소 작업은 본질적으로 병렬화 할 수 있습니다. ) 요소를 처리하는 데 사용되는 것은 연관성 이며 상태 비 저장 입니다. “
밀접하게 관련된 Collector에 대한 문서 는 훨씬 더 명확합니다. ” 순차 및 병렬 실행이 동등한 결과를 생성하도록 하려면 수집기 함수가 ID 및 연관성 제약 조건을 충족해야합니다 .”
원래 질문으로 돌아 가기 : 다음 코드는 변수의 마지막 요소에 대한 참조를 저장 last
하고 스트림이 비어있는 경우 예외를 발생시킵니다. 복잡성은 스트림의 길이에 선형 적입니다.
CArea last = data.careas
.stream()
.filter(c -> c.bbox.orientationHorizontal)
.reduce((first, second) -> second).get();
답변
컬렉션 (또는 더 일반적인 Iterable)이있는 경우 Google Guava의
Iterables.getLast(myIterable)
편리한 oneliner로.
답변
라이너 1 개 (흐름 불필요) :
Object lastElement = list.get(list.size()-1);
답변
Guava에는이 경우에 대한 전용 방법이 있습니다.
Stream<T> stream = ...;
Optional<T> lastItem = Streams.findLast(stream);
이와 동등 stream.reduce((a, b) -> b)
하지만 제작자는 훨씬 더 나은 성능을 제공한다고 주장합니다.
에서 문서 :
이 메서드의 런타임은 O (log n)와 O (n) 사이에 있으며 효율적으로 분할 가능한 스트림에서 더 잘 수행됩니다.
스트림의 순서가 지정되지 않은 경우이 메서드는 findAny()
.
답변
마지막 N 개의 요소를 가져와야하는 경우. 클로저를 사용할 수 있습니다. 아래 코드는 스트림이 끝날 때까지 고정 된 크기의 외부 큐를 유지합니다.
final Queue<Integer> queue = new LinkedList<>();
final int N=5;
list.stream().peek((z) -> {
queue.offer(z);
if (queue.size() > N)
queue.poll();
}).count();
또 다른 옵션은 ID를 대기열로 사용하여 축소 작업을 사용하는 것입니다.
final int lastN=3;
Queue<Integer> reduce1 = list.stream()
.reduce(
(Queue<Integer>)new LinkedList<Integer>(),
(m, n) -> {
m.offer(n);
if (m.size() > lastN)
m.poll();
return m;
}, (m, n) -> m);
System.out.println("reduce1 = " + reduce1);
답변
다음과 같이 skip () 함수를 사용할 수도 있습니다.
long count = data.careas.count();
CArea last = data.careas.stream().skip(count - 1).findFirst().get();
사용하기 매우 간단합니다.