술어로 스트림 제한
a(잠재적으로 무한 확장)를 제한하는 Java 8 스트림 작업이 있는가?Stream
첫 번째 요소가 술어와 일치하지 않을 때까지?
Java 9에서 우리는 사용할 수 있다.takeWhile
아래 예시와 같이 10보다 작은 모든 숫자를 인쇄한다.
IntStream
.iterate(1, n -> n + 1)
.takeWhile(n -> n < 10)
.forEach(System.out::println);
자바 8에는 그런 운영이 없기 때문에 일반적인 방법으로 실행하는 것이 가장 좋은 방법은 무엇일까?
영takeWhile
그리고dropWhile
JDK 9에 추가됨. 예시 코드
IntStream
.iterate(1, n -> n + 1)
.takeWhile(n -> n < 10)
.forEach(System.out::println);
JDK 9에 따라 컴파일되고 실행될 때 당신이 예상하는 대로 정확하게 행동할 것이다.
JDK 9가 나왔다.여기에서 JDK 9 릴리즈를 다운로드할 수 있다.
그러한 작전은 자바 8로 가능해야 한다.Stream
, 그러나 그것이 반드시 효율적으로 수행될 수는 없다. 예를 들어, 요소들을 순서대로 살펴야 하는 것처럼, 그러한 작업을 반드시 병행할 수는 없다.
API가 쉬운 방법은 아니지만, 가장 간단한 방법은Stream.iterator()
, "Take-the-time" 구현을 위해 포장한 다음 다시 로 돌아가십시오.Spliterator
그리고 나서 aStream
. 또는 -- 아마도 -- 이 구현에서는 더 이상 분할할 수 없지만 포장하십시오.
되지 않은 스스지지은의 takeWhile
에서Spliterator
:
static <T> Spliterator<T> takeWhile(
Spliterator<T> splitr, Predicate<? super T> predicate) {
return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) {
boolean stillGoing = true;
@Override public boolean tryAdvance(Consumer<? super T> consumer) {
if (stillGoing) {
boolean hadNext = splitr.tryAdvance(elem -> {
if (predicate.test(elem)) {
consumer.accept(elem);
} else {
stillGoing = false;
}
});
return hadNext && stillGoing;
}
return false;
}
};
}
static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> predicate) {
return StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false);
}
allMatch()
단락 기능이기 때문에, 당신은 그것을 처리를 멈추는데 사용할 수 있다.가장 큰 단점은 시험을 두 번 해야 한다는 것이다. 시험을 한 번 치러야 하는지, 그리고 계속 진행해야 하는지 다시 한 번.
IntStream
.iterate(1, n -> n + 1)
.peek(n->{if (n<10) System.out.println(n);})
.allMatch(n->n < 10);
@StuartMarks의 후속 답변으로.내 StreamEx 라이브러리에는 현재 JDK-9 구현과 호환되는 작업이 있다.JDK-9에서 실행될 경우 JDK 구현에 위임만 할 뿐(이를 통해)MethodHandle.invokeExact
그것은 정말 빠르다.JDK-8로 실행될 경우, "폴리필" 구현이 사용될 것이다.그래서 내 도서관을 이용하면 다음과 같이 문제를 해결할 수 있다.
IntStreamEx.iterate(1, n -> n + 1)
.takeWhile(n -> n < 10)
.forEach(System.out::println);
takeWhile
프로토 팩 라이브러리가 제공하는 기능 중 하나이다.
Stream<Integer> infiniteInts = Stream.iterate(0, i -> i + 1);
Stream<Integer> finiteInts = StreamUtils.takeWhile(infiniteInts, i -> i < 10);
assertThat(finiteInts.collect(Collectors.toList()),
hasSize(10));
9 업이이: Java 9Stream
이제 곧 기회가 온다.방법론에서.
해킹이나 다른 해결책이 필요하지 않다.그냥 그거 써!
나는 이것이 크게 개선될 수 있다고 확신한다: (누군가가 그것을 안전하게 만들 수 있을지도 모른다)
Stream<Integer> stream = Stream.iterate(0, n -> n + 1);
TakeWhile.stream(stream, n -> n < 10000)
.forEach(n -> System.out.print((n == 0 ? "" + n : "," + n)));
해킹은 확실히...우아하지는 않지만 ~:D로 작동함
class TakeWhile<T> implements Iterator<T> {
private final Iterator<T> iterator;
private final Predicate<T> predicate;
private volatile T next;
private volatile boolean keepGoing = true;
public TakeWhile(Stream<T> s, Predicate<T> p) {
this.iterator = s.iterator();
this.predicate = p;
}
@Override
public boolean hasNext() {
if (!keepGoing) {
return false;
}
if (next != null) {
return true;
}
if (iterator.hasNext()) {
next = iterator.next();
keepGoing = predicate.test(next);
if (!keepGoing) {
next = null;
}
}
return next != null;
}
@Override
public T next() {
if (next == null) {
if (!hasNext()) {
throw new NoSuchElementException("Sorry. Nothing for you.");
}
}
T temp = next;
next = null;
return temp;
}
public static <T> Stream<T> stream(Stream<T> s, Predicate<T> p) {
TakeWhile tw = new TakeWhile(s, p);
Spliterator split = Spliterators.spliterator(tw, Integer.MAX_VALUE, Spliterator.ORDERED);
return StreamSupport.stream(split, false);
}
}
자바8 + rxjava를 사용할 수 있다.
import java.util.stream.IntStream;
import rx.Observable;
// Example 1)
IntStream intStream = IntStream.iterate(1, n -> n + 1);
Observable.from(() -> intStream.iterator())
.takeWhile(n ->
{
System.out.println(n);
return n < 10;
}
).subscribe() ;
// Example 2
IntStream intStream = IntStream.iterate(1, n -> n + 1);
Observable.from(() -> intStream.iterator())
.takeWhile(n -> n < 10)
.forEach( n -> System.out.println(n));
실제로 별도의 라이브러리 없이 자바 8에서 하는 방법과 자바 9를 사용하는 방법에는 두 가지가 있다.
콘솔에서 2에서 20까지의 숫자를 인쇄하려면 다음을 수행하십시오.
IntStream.iterate(2, (i) -> i + 2).peek(System.out::println).allMatch(i -> i < 20);
또는
IntStream.iterate(2, (i) -> i + 2).peek(System.out::println).anyMatch(i -> i >= 20);
출력은 두 가지 경우 모두 다음과 같다.
2
4
6
8
10
12
14
16
18
20
아직 아무도 Match에 대해 언급하지 않았다.이것이 이 게시물의 이유야.
이것은 JDK 9 java.util.stream에서 복사한 원본이다.스트림.테이크한편(Predicate).JDK 8과 함께 일하기 위해서는 약간의 차이가 있다.
static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> p) {
class Taking extends Spliterators.AbstractSpliterator<T> implements Consumer<T> {
private static final int CANCEL_CHECK_COUNT = 63;
private final Spliterator<T> s;
private int count;
private T t;
private final AtomicBoolean cancel = new AtomicBoolean();
private boolean takeOrDrop = true;
Taking(Spliterator<T> s) {
super(s.estimateSize(), s.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED));
this.s = s;
}
@Override
public boolean tryAdvance(Consumer<? super T> action) {
boolean test = true;
if (takeOrDrop && // If can take
(count != 0 || !cancel.get()) && // and if not cancelled
s.tryAdvance(this) && // and if advanced one element
(test = p.test(t))) { // and test on element passes
action.accept(t); // then accept element
return true;
} else {
// Taking is finished
takeOrDrop = false;
// Cancel all further traversal and splitting operations
// only if test of element failed (short-circuited)
if (!test)
cancel.set(true);
return false;
}
}
@Override
public Comparator<? super T> getComparator() {
return s.getComparator();
}
@Override
public void accept(T t) {
count = (count + 1) & CANCEL_CHECK_COUNT;
this.t = t;
}
@Override
public Spliterator<T> trySplit() {
return null;
}
}
return StreamSupport.stream(new Taking(stream.spliterator()), stream.isParallel()).onClose(stream::close);
}
여기 ints에서 한 버전이 있다 - 질문에서 물어본 대로.
사용량:
StreamUtil.takeWhile(IntStream.iterate(1, n -> n + 1), n -> n < 10);
StreamUtil에 대한 코드:
import java.util.PrimitiveIterator;
import java.util.Spliterators;
import java.util.function.IntConsumer;
import java.util.function.IntPredicate;
import java.util.stream.IntStream;
import java.util.stream.StreamSupport;
public class StreamUtil
{
public static IntStream takeWhile(IntStream stream, IntPredicate predicate)
{
return StreamSupport.intStream(new PredicateIntSpliterator(stream, predicate), false);
}
private static class PredicateIntSpliterator extends Spliterators.AbstractIntSpliterator
{
private final PrimitiveIterator.OfInt iterator;
private final IntPredicate predicate;
public PredicateIntSpliterator(IntStream stream, IntPredicate predicate)
{
super(Long.MAX_VALUE, IMMUTABLE);
this.iterator = stream.iterator();
this.predicate = predicate;
}
@Override
public boolean tryAdvance(IntConsumer action)
{
if (iterator.hasNext()) {
int value = iterator.nextInt();
if (predicate.test(value)) {
action.accept(value);
return true;
}
}
return false;
}
}
}
라이브러리 AbacusUtil을 다운로드하십시오.원하는 API 및 기타 기능을 제공한다.
IntStream.iterate(1, n -> n + 1).takeWhile(n -> n < 10).forEach(System.out::println);
선언: 나는 아바쿠스유틸의 개발자다.
수행될 정확한 회수의 양을 알면 할 수 있다.
IntStream
.iterate(1, n -> n + 1)
.limit(10)
.forEach(System.out::println);
IntStream.iterate(1, n -> n + 1)
.peek(System.out::println) //it will be executed 9 times
.filter(n->n>=9)
.findAny();
peak 대신 mapToObj를 사용하여 최종 객체 또는 메시지를 반환할 수 있음
IntStream.iterate(1, n -> n + 1)
.mapToObj(n->{ //it will be executed 9 times
if(n<9)
return "";
return "Loop repeats " + n + " times";});
.filter(message->!message.isEmpty())
.findAny()
.ifPresent(System.out::println);
일부 스트림 값은 값에 관계없이 처리되지 않는 단락 단자 작동 외에는 스트림을 중단할 수 없다.그러나 스트림에서 작업을 수행하지 않으려면 스트림에 변환 및 필터를 추가하십시오.
import java.util.Objects;
class ThingProcessor
{
static Thing returnNullOnCondition(Thing thing)
{ return( (*** is condition met ***)? null : thing); }
void processThings(Collection<Thing> thingsCollection)
{
thingsCollection.stream()
*** regular stream processing ***
.map(ThingProcessor::returnNullOnCondition)
.filter(Objects::nonNull)
*** continue stream processing ***
}
} // class ThingProcessor
어떤 조건을 충족하면 사물의 흐름을 무효로 바꾼 다음, 무효를 걸러낸다.부작용에 빠져들 의향이 있다면 일단 어떤 것이 부딪히면 조건 값을 참으로 설정할 수 있기 때문에 이후의 모든 것들은 그 가치에 관계없이 걸러진다.그러나 그렇지 않더라도 처리하지 않으려는 스트림에서 값을 필터링하여 많은(전부는 아닐 경우) 처리를 저장할 수 있다.
비슷한 요구 사항이 있었는데도 웹 서비스를 호출하고, 실패할 경우 3번 다시 시도하십시오.이렇게 많은 시행 후에도 실패하면 이메일 알림을 보내십시오.구글을 많이 검색해보니anyMatch()
구세주로서 왔다.나의 샘플 코드는 다음과 같다.다음 예에서 webServiceCall 방법이 첫 번째 반복 자체에서 true로 반환되는 경우 스트림은 우리가 호출한 대로 더 이상 반복되지 않는다.anyMatch()
난 네가 찾고 있는 게 바로 이것이라고 믿어.
import java.util.stream.IntStream;
import io.netty.util.internal.ThreadLocalRandom;
class TrialStreamMatch {
public static void main(String[] args) {
if(!IntStream.range(1,3).anyMatch(integ -> webServiceCall(integ))){
//Code for sending email notifications
}
}
public static boolean webServiceCall(int i){
//For time being, I have written a code for generating boolean randomly
//This whole piece needs to be replaced by actual web-service client code
boolean bool = ThreadLocalRandom.current().nextBoolean();
System.out.println("Iteration index :: "+i+" bool :: "+bool);
//Return success status -- true or false
return bool;
}
만약 당신이 다른 문제를 가지고 있다면, 다른 해결책이 필요할지도 모르지만, 당신의 현재 문제에 대해서, 나는 간단히 다음과 같이 할 것이다.
IntStream
.iterate(1, n -> n + 1)
.limit(10)
.forEach(System.out::println);
주제에서 약간 벗어나겠지만, 이것이 우리가 원하는 것이다.List<T>
Stream<T>
.
먼저, 당신은 A를 가져야 한다.take
활용 방법이 방법이 우선이다.n
요소:
static <T> List<T> take(List<T> l, int n) {
if (n <= 0) {
return newArrayList();
} else {
int takeTo = Math.min(Math.max(n, 0), l.size());
return l.subList(0, takeTo);
}
}
그것은 그냥 처럼 작동한다.scala.List.take
assertEquals(newArrayList(1, 2, 3), take(newArrayList(1, 2, 3, 4, 5), 3));
assertEquals(newArrayList(1, 2, 3), take(newArrayList(1, 2, 3), 5));
assertEquals(newArrayList(), take(newArrayList(1, 2, 3), -1));
assertEquals(newArrayList(), take(newArrayList(1, 2, 3), 0));
이제 a를 쓰는 것은 꽤 간단할 것이다.takeWhile
에 기반을 둔 방법take
static <T> List<T> takeWhile(List<T> l, Predicate<T> p) {
return l.stream().
filter(p.negate()).findFirst(). // find first element when p is false
map(l::indexOf). // find the index of that element
map(i -> take(l, i)). // take up to the index
orElse(l); // return full list if p is true for all elements
}
다음과 같이 작동한다.
assertEquals(newArrayList(1, 2, 3), takeWhile(newArrayList(1, 2, 3, 4, 3, 2, 1), i -> i < 4));
이 구현은 목록을 부분적으로 몇 번 반복하지만 추가하지는 않는다.O(n^2)
例 바란다그게 받아들여지길 바래.
나는 이것을 실행함으로써 또 다른 빠른 해결책을 가지고 있다(사실 부정적이지만, 당신은 그 생각을 알 수 있다).
public static void main(String[] args) {
System.out.println(StreamUtil.iterate(1, o -> o + 1).terminateOn(15)
.map(o -> o.toString()).collect(Collectors.joining(", ")));
}
static interface TerminatedStream<T> {
Stream<T> terminateOn(T e);
}
static class StreamUtil {
static <T> TerminatedStream<T> iterate(T seed, UnaryOperator<T> op) {
return new TerminatedStream<T>() {
public Stream<T> terminateOn(T e) {
Builder<T> builder = Stream.<T> builder().add(seed);
T current = seed;
while (!current.equals(e)) {
current = op.apply(current);
builder.add(current);
}
return builder.build();
}
};
}
}
자바 스트림 라이브러리만 사용해 보십시오.
IntStream.iterate(0, i -> i + 1)
.filter(n -> {
if (n < 10) {
System.out.println(n);
return false;
} else {
return true;
}
})
.findAny();
참조URL: https://stackoverflow.com/questions/20746429/limit-a-stream-by-a-predicate
'programing' 카테고리의 다른 글
윈도우즈에서 https를 사용하여 Vue-cli 프로젝트를 실행하는 방법 (0) | 2022.05.13 |
---|---|
C 빈 구조체 - 이것은 무엇을 의미하나? (0) | 2022.05.13 |
vue에서 어레이를 모델로 사용하는 경우 확인란 값을 가져오는 방법 (0) | 2022.05.13 |
변수에 레이블 주소를 저장하고 goto를 사용하여 해당 주소로 이동할 수 있는가? (0) | 2022.05.13 |
Vue Js의 Javascript 파일에서 상태 값 업데이트 (0) | 2022.05.13 |