[SCALA] 자바 8 스트림, 점점 머리와 꼬리
SCALA자바 8 스트림, 점점 머리와 꼬리
자바 8 스칼라의 스트림, 매우 간결 같은 것을 할 수 있습니다 사용하여 강력한 게으른 구조와 유사한 스트림 클래스를 소개 :
def from(n: Int): Stream[Int] = n #:: from(n+1)
def sieve(s: Stream[Int]): Stream[Int] = {
s.head #:: sieve(s.tail filter (_ % s.head != 0))
}
val primes = sieve(from(2))
primes takeWhile(_ < 1000) print // prints all primes less than 1000
이 자바 8에서이 작업을 수행 할 수 있다면이 같은 것을 쓴, 그래서 내가 궁금 :
IntStream from(int n) {
return IntStream.iterate(n, m -> m + 1);
}
IntStream sieve(IntStream s) {
int head = s.findFirst().getAsInt();
return IntStream.concat(IntStream.of(head), sieve(s.skip(1).filter(n -> n % head != 0)));
}
IntStream primes = sieve(from(2));
매우 간단하지만 java.lang.IllegalStateException가 생성 () 스트림이 이미 동작시 또는 둘다로 findFirst 때문에 () 및 폐쇄 이동 한 번만 수행 될 수 스트림에서 단말기 동작이다.
나는 정말로 내가 필요 스칼라의 Stream.head 및 Stream.tail의 해당 스트림의 첫 번째 숫자와 다른 스트림으로 나머지, 즉 때문에 두 번 스트림을 사용할 필요가 없습니다. 나는 이것을 달성하는 데 사용할 수있는 자바 (8) 스트림의 방법이 있습니까?
감사.
해결법
-
==============================
1.당신은 당신이 IntStream을 분할 할 수 없다는 문제가없는 한 경우에도 재귀 대신 느리게 당신의 체 메소드를 호출하기 때문에, 당신의 코드는 일을하지 않았다. 첫 번째 값에 대한 결과의 스트림을 조회하기 전에 그래서 당신은 무한 재귀했다.
당신은 당신이 IntStream을 분할 할 수 없다는 문제가없는 한 경우에도 재귀 대신 느리게 당신의 체 메소드를 호출하기 때문에, 당신의 코드는 일을하지 않았다. 첫 번째 값에 대한 결과의 스트림을 조회하기 전에 그래서 당신은 무한 재귀했다.
IntStream는 머리와 꼬리 IntStream (아직 소비되지 않은)로 변환하는 분할이 가능하다 :
PrimitiveIterator.OfInt it = s.iterator(); int head = it.nextInt(); IntStream tail = IntStream.generate(it::next).filter(i -> i % head != 0);
이 곳에서 당신은 느리게 꼬리에 체를 호출하는 구조가 필요합니다. 스트림은 제공하지 않습니다; CONCAT 인수로 스트림 인스턴스를 기존 예상하는 게으른 창조 람다 표현식을 지원하지 않는 경우에만 변경 가능한 상태로 작동하기 때문에 당신은 람다 식으로 체 유유히 호출 스트림을 구성 할 수 없습니다. 당신이 라이브러리 구현이 변경 가능한 상태를 숨기고이없는 경우에는 변경 가능한 객체를 사용합니다. 당신이 변경 가능한 상태의 요구 사항을 수용하지만 일단이 솔루션은 첫 번째 방법보다 쉽게 할 수 있습니다 :
IntStream primes = from(2).filter(i -> p.test(i)).peek(i -> p = p.and(v -> v % i != 0)); IntPredicate p = x -> true; IntStream from(int n) { return IntStream.iterate(n, m -> m + 1); }
이 재귀 적 필터를 만들하지만 (이 작업을 한 경우 IntStream.concat 접근 방식처럼) 결국이 문제는 IntPredicates의 나무 또는 IntStreams의 트리를 만들지 않습니다 여부를 지정합니다. 당신은 필터의 가변 인스턴스 필드 마음에 들지 않으면 당신은 (...하지만 람다 식의) 내부 클래스에서 숨길 수 있습니다.
-
==============================
2.이 솔루션은 아래 스트림의 헤드 / 테일 해체를 제외하고, 상태 변이를하지 않습니다.
이 솔루션은 아래 스트림의 헤드 / 테일 해체를 제외하고, 상태 변이를하지 않습니다.
게으름은 IntStream.iterate를 사용하여 얻어진다. 클래스 총리는 발전기 상태를 유지하는 데 사용됩니다
import java.util.PrimitiveIterator; import java.util.stream.IntStream; import java.util.stream.Stream; public class Prime { private final IntStream candidates; private final int current; private Prime(int current, IntStream candidates) { this.current = current; this.candidates = candidates; } private Prime next() { PrimitiveIterator.OfInt it = candidates.filter(n -> n % current != 0).iterator(); int head = it.next(); IntStream tail = IntStream.generate(it::next); return new Prime(head, tail); } public static Stream<Integer> stream() { IntStream possiblePrimes = IntStream.iterate(3, i -> i + 1); return Stream.iterate(new Prime(2, possiblePrimes), Prime::next) .map(p -> p.current); } }
사용법이 될 것입니다 :
Stream<Integer> first10Primes = Prime.stream().limit(10)
-
==============================
3.내 StreamEx 라이브러리는 문제를 해결 지금 headTail () 작업이 있습니다 :
내 StreamEx 라이브러리는 문제를 해결 지금 headTail () 작업이 있습니다 :
public static StreamEx<Integer> sieve(StreamEx<Integer> input) { return input.headTail((head, tail) -> sieve(tail.filter(n -> n % head != 0)).prepend(head)); }
headTail 방법은 일단 스트림 단말기 동작 실행 중에 많아야 실행될 것이다 BiFunction 걸린다. 이 탐색이 시작 될 때까지 계산 아무것도하지 않습니다 및 요청에 따라 단지 많은 소수로 계산 :이 구현은 게으른 그래서. BiFunction은 제 스트림 요소 머리와 나머지 요소 꼬리의 스트림을 수신하고 원하는 어떤 방법으로 꼬리를 수정할 수 있습니다. 미리 정의 된 입력으로 사용할 수 있습니다 :
sieve(IntStreamEx.range(2, 1000).boxed()).forEach(System.out::println);
그러나 무한 스트림 작업뿐만 아니라
sieve(StreamEx.iterate(2, x -> x+1)).takeWhile(x -> x < 1000) .forEach(System.out::println); // Not the primes till 1000, but 1000 first primes sieve(StreamEx.iterate(2, x -> x+1)).limit(1000).forEach(System.out::println);
headTail와 술어 연결을 사용하여 대체 솔루션도 있습니다 :
public static StreamEx<Integer> sieve(StreamEx<Integer> input, IntPredicate isPrime) { return input.headTail((head, tail) -> isPrime.test(head) ? sieve(tail, isPrime.and(n -> n % head != 0)).prepend(head) : sieve(tail, isPrime)); } sieve(StreamEx.iterate(2, x -> x+1), i -> true).limit(1000).forEach(System.out::println);
그것은 흥미로운 재귀 솔루션을 비교 : 그들이 할 수있는 생성하는 방법을 많은 소수.
소매점을 @ 존 용액 (StreamUtils)
존 서 소매점 솔루션은 게으른하지 않은 : 당신은 무한 스트림을 공급되지 않습니다. 난 그냥 시행 착오에 의해 발견 그래서 상 허용되는 최대 바운드 (17793) (StackOverflowError가 발생 그 후) :
public void sieveTest(){ sieve(IntStream.range(2, 17793).boxed()).forEach(System.out::println); }
소매점을 @ 존 용액 (Streamable의)
public void sieveTest2(){ sieve(Streamable.range(2, 39990)).forEach(System.out::println); }
StackOverflowError가에서 39,990 결과 위의 상한을 증가.
@frhack 용액 (LazySeq)
LazySeq<Integer> ints = integers(2); LazySeq primes = sieve(ints); // sieve method from @frhack answer primes.forEach(p -> System.out.println(p));
결과 : 엄청난 힙 할당 및 가비지 컬렉션이 90 % 이상을 복용 소수 = 53327 후 붙어. 더 기다리는 것은 비현실적 보인다 그래서는 53,323에서 53,327에 사전에 몇 분했다.
@ 신 솔루션
Prime.stream().forEach(System.out::println);
결과 : StackOverflowError가를 소수 = 134417 후.
내 솔루션 (StreamEx)
sieve(StreamEx.iterate(2, x -> x+1)).forEach(System.out::println);
결과 : StackOverflowError가를 소수 = 236167 후.
@frhack 용액 (rxjava)
Observable<Integer> primes = Observable.from(()->primesStream.iterator()); primes.forEach((x) -> System.out.println(x.toString()));
결과 : StackOverflowError가를 소수 = 367663 후.
@Holger 솔루션
IntStream primes=from(2).filter(i->p.test(i)).peek(i->p=p.and(v->v%i!=0)); primes.forEach(System.out::println);
결과 : StackOverflowError가를 소수 = 368089 후.
내 솔루션 (술어 연결과 StreamEx)
sieve(StreamEx.iterate(2, x -> x+1), i -> true).forEach(System.out::println);
결과 : StackOverflowError가를 소수 = 368287 후.
각각의 새로운 조건은 2 개 스택 프레임을 추가하기 때문에, 술어 연결 승리를 포함하는 세 가지 솔루션 그래서. 나는 그들 사이의 차이가 한계이며 승자를 정의하는 것으로 간주되어서는 안된다 생각합니다. 그러나 나는 처음 StreamEx 솔루션 같은 더으로 스칼라 코드와 더 유사합니다.
-
==============================
4.당신은 기본적으로 다음과 같이 그것을 구현할 수 있습니다 :
당신은 기본적으로 다음과 같이 그것을 구현할 수 있습니다 :
static <T> Tuple2<Optional<T>, Seq<T>> splitAtHead(Stream<T> stream) { Iterator<T> it = stream.iterator(); return tuple(it.hasNext() ? Optional.of(it.next()) : Optional.empty(), seq(it)); }
위의 예에서, Tuple2 서열은 jOOλ, 우리가 jOOQ 통합 테스트를 위해 개발 한 도서관에서 빌린 종류가 있습니다. 당신이 추가 종속성을 원하지 않는 경우, 당신은뿐만 아니라 그들에게 자신을 구현할 수 :
class Tuple2<T1, T2> { final T1 v1; final T2 v2; Tuple2(T1 v1, T2 v2) { this.v1 = v1; this.v2 = v2; } static <T1, T2> Tuple2<T1, T2> tuple(T1 v1, T2 v2) { return new Tuple<>(v1, v2); } } static <T> Tuple2<Optional<T>, Stream<T>> splitAtHead(Stream<T> stream) { Iterator<T> it = stream.iterator(); return tuple( it.hasNext() ? Optional.of(it.next()) : Optional.empty, StreamSupport.stream(Spliterators.spliteratorUnknownSize( it, Spliterator.ORDERED ), false) ); }
-
==============================
5.당신이 제 3의 라이브러리의 외눈 박이 스트림을 사용하여 괜찮다면, 나는 도서관 나는 잠재적 인 솔루션을 가지고 있습니다 썼다.
당신이 제 3의 라이브러리의 외눈 박이 스트림을 사용하여 괜찮다면, 나는 도서관 나는 잠재적 인 솔루션을 가지고 있습니다 썼다.
StreamUtils 클래스는 headAndTail 포함 java.util.stream.Streams 직접 작업을위한 정적 메소드의 많은 수 있습니다.
HeadAndTail<Integer> headAndTail = StreamUtils.headAndTail(Stream.of(1,2,3,4)); int head = headAndTail.head(); //1 Stream<Integer> tail = headAndTail.tail(); //Stream[2,3,4]
Streamable의 클래스는 replayable 스트림을 나타내는 중간 데이터 구조를 캐싱, 게으른을 구축하여 작동합니다. 이 캐시되어 있기 때문에 상환 - 머리와 꼬리는 직접 개별적으로 구현 될 수있다.
Streamable<Integer> replayable= Streamable.fromStream(Stream.of(1,2,3,4)); int head = repayable.head(); //1 Stream<Integer> tail = replayable.tail(); //Stream[2,3,4]
사이클롭스 스트림도 차례로 jOOλ 연장 모두 튜플 (jOOλ부터) 기반 것을 순차 스트림 확장을 제공하며, 머리와 꼬리 추출 도메인 개체 (HeadAndTail) 솔루션.
SequenceM.of(1,2,3,4) .splitAtHead(); //Tuple[1,SequenceM[2,3,4] SequenceM.of(1,2,3,4) .headAndTail();
Tagir의 요청에 따라 업데이트 -> 스칼라의 자바 버전은 SequenceM를 사용하여 체
public void sieveTest(){ sieve(SequenceM.range(2, 1_000)).forEach(System.out::println); } SequenceM<Integer> sieve(SequenceM<Integer> s){ return s.headAndTailOptional().map(ht ->SequenceM.of(ht.head()) .appendStream(sieve(ht.tail().filter(n -> n % ht.head() != 0)))) .orElse(SequenceM.of()); }
그리고 Streamable를 통해 다른 버전
public void sieveTest2(){ sieve(Streamable.range(2, 1_000)).forEach(System.out::println); } Streamable<Integer> sieve(Streamable<Integer> s){ return s.size()==0? Streamable.of() : Streamable.of(s.head()) .appendStreamable(sieve(s.tail() .filter(n -> n % s.head() != 0))); }
주 - 따라서 Streamable의의 크기 확인 및 headAndTailOptional의 사용 - SequenceM의 Streamable의도는 빈 구현이있다.
마지막 버전은 일반 java.util.stream.Stream를 사용하여
import static com.aol.cyclops.streams.StreamUtils.headAndTailOptional; public void sieveTest(){ sieve(IntStream.range(2, 1_000).boxed()).forEach(System.out::println); } Stream<Integer> sieve(Stream<Integer> s){ return headAndTailOptional(s).map(ht ->Stream.concat(Stream.of(ht.head()) ,sieve(ht.tail().filter(n -> n % ht.head() != 0)))) .orElse(Stream.of()); }
또 다른 업데이트 - 프리미티브가 아닌 객체를 사용하여 홀거 버전 @ 기반으로 게으른 반복적 인 (주 원시적 버전도 가능)
final Mutable<Predicate<Integer>> predicate = Mutable.of(x->true); SequenceM.iterate(2, n->n+1) .filter(i->predicate.get().test(i)) .peek(i->predicate.mutate(p-> p.and(v -> v%i!=0))) .limit(100000) .forEach(System.out::println);
-
==============================
6.머리와 꼬리를 얻으려면 당신은 게으른 스트림 구현이 필요합니다. 자바 8 스트림 또는 RxJava는 적합하지 않습니다.
머리와 꼬리를 얻으려면 당신은 게으른 스트림 구현이 필요합니다. 자바 8 스트림 또는 RxJava는 적합하지 않습니다.
다음과 같이 예를 들어 LazySeq에 사용할 수 있습니다.
package com.company; import com.nurkiewicz.lazyseq.LazySeq; public class Main { public static void main(String[] args) { LazySeq<Integer> ints = integers(2); LazySeq primes = sieve(ints); primes.take(10).forEach(p -> System.out.println(p)); } private static LazySeq<Integer> sieve(LazySeq<Integer> s) { return LazySeq.cons(s.head(), () -> sieve(s.filter(x -> x % s.head() != 0))); } private static LazySeq<Integer> integers(int from) { return LazySeq.cons(from, () -> integers(from + 1)); } }
-
==============================
7.여기 홀거에 의해 제안 된 방법을 사용하여 다른 조리법이다. 그냥 테이크 (int) 메소드 및 많은 다른 사람을 사용할 수있는 가능성을 추가 RxJava를 사용합니다.
여기 홀거에 의해 제안 된 방법을 사용하여 다른 조리법이다. 그냥 테이크 (int) 메소드 및 많은 다른 사람을 사용할 수있는 가능성을 추가 RxJava를 사용합니다.
package com.company; import rx.Observable; import java.util.function.IntPredicate; import java.util.stream.IntStream; public class Main { public static void main(String[] args) { final IntPredicate[] p={(x)->true}; IntStream primesStream=IntStream.iterate(2,n->n+1).filter(i -> p[0].test(i)).peek(i->p[0]=p[0].and(v->v%i!=0) ); Observable primes = Observable.from(()->primesStream.iterator()); primes.take(10).forEach((x) -> System.out.println(x.toString())); } }
-
==============================
8.이 여기에 제공된 많은 흥미로운 제안이 있지만, 누군가가 타사 라이브러리에 의존하지 않고 솔루션을 필요로하는 경우 나는이 함께했다 :
이 여기에 제공된 많은 흥미로운 제안이 있지만, 누군가가 타사 라이브러리에 의존하지 않고 솔루션을 필요로하는 경우 나는이 함께했다 :
import java.util.AbstractMap; import java.util.Optional; import java.util.Spliterators; import java.util.stream.StreamSupport; /** * Splits a stream in the head element and a tail stream. * Parallel streams are not supported. * * @param stream Stream to split. * @param <T> Type of the input stream. * @return A map entry where {@link Map.Entry#getKey()} contains an * optional with the first element (head) of the original stream * and {@link Map.Entry#getValue()} the tail of the original stream. * @throws IllegalArgumentException for parallel streams. */ public static <T> Map.Entry<Optional<T>, Stream<T>> headAndTail(final Stream<T> stream) { if (stream.isParallel()) { throw new IllegalArgumentException("parallel streams are not supported"); } final Iterator<T> iterator = stream.iterator(); return new AbstractMap.SimpleImmutableEntry<>( iterator.hasNext() ? Optional.of(iterator.next()) : Optional.empty(), StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false) ); }
-
==============================
9.당신은, 스트림의 머리를 얻고 싶다면 :
당신은, 스트림의 머리를 얻고 싶다면 :
IntStream.range(1, 5).first();
당신이 스트림의 꼬리를 얻고 싶은 경우에, 다만 :
IntStream.range(1, 5).skip(1);
당신은, 스트림의 양쪽 머리와 꼬리를 얻고 싶다면 :
IntStream s = IntStream.range(1, 5); int head = s.head(); IntStream tail = s.tail();
당신이 총리를 찾으려면, 단지 :
LongStream.range(2, n) .filter(i -> LongStream.range(2, (long) Math.sqrt(i) + 1).noneMatch(j -> i % j == 0)) .forEach(N::println);
더 알고 싶은 경우에, AbacusUtil를 얻을로 이동
선언 : 나는 AbacusUtil의 개발자입니다.
from https://stackoverflow.com/questions/19803058/java-8-stream-getting-head-and-tail by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 스칼라 케이스 클래스에 업데이트 작업 (0) | 2019.11.09 |
---|---|
[SCALA] 두 목록의 직교 제품 (0) | 2019.11.09 |
[SCALA] 자바 8 스트림 API와 정수의 목록을 셔플 (0) | 2019.11.09 |
[SCALA] 스칼라에서 제네릭 형식에 대한 패턴 매칭 (0) | 2019.11.09 |
[SCALA] 왜`배열 (0,1,2) == 배열 (0,1,2)`예상 된 결과를 반환하지 않습니다? (0) | 2019.11.09 |