com.aol.cyclops.streams.StreamUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cyclops-streams Show documentation
Show all versions of cyclops-streams Show documentation
Sequential Streams and Stream Utilities for Java 8
package com.aol.cyclops.streams;
import java.io.BufferedReader;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.BaseStream;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import lombok.AllArgsConstructor;
import lombok.experimental.UtilityClass;
import org.jooq.lambda.Seq;
import org.jooq.lambda.tuple.Tuple2;
import org.jooq.lambda.tuple.Tuple3;
import org.jooq.lambda.tuple.Tuple4;
import org.pcollections.ConsPStack;
import org.pcollections.PStack;
import com.aol.cyclops.closures.mutable.Mutable;
import com.aol.cyclops.internal.AsGenericMonad;
import com.aol.cyclops.invokedynamic.ExceptionSoftener;
import com.aol.cyclops.monad.AnyM;
import com.aol.cyclops.sequence.HeadAndTail;
import com.aol.cyclops.sequence.HotStream;
import com.aol.cyclops.sequence.Monoid;
import com.aol.cyclops.sequence.ReversedIterator;
import com.aol.cyclops.sequence.SeqUtils;
import com.aol.cyclops.sequence.SequenceM;
import com.aol.cyclops.sequence.SequenceMImpl;
import com.aol.cyclops.sequence.future.FutureOperations;
import com.aol.cyclops.sequence.spliterators.ReversableSpliterator;
import com.aol.cyclops.sequence.streamable.AsStreamable;
import com.aol.cyclops.sequence.streamable.Streamable;
import com.aol.cyclops.streams.future.FutureOperationsImpl;
import com.aol.cyclops.streams.operators.BatchBySizeOperator;
import com.aol.cyclops.streams.operators.BatchByTimeAndSizeOperator;
import com.aol.cyclops.streams.operators.BatchByTimeOperator;
import com.aol.cyclops.streams.operators.BatchWhileOperator;
import com.aol.cyclops.streams.operators.DebounceOperator;
import com.aol.cyclops.streams.operators.LimitLastOperator;
import com.aol.cyclops.streams.operators.LimitWhileOperator;
import com.aol.cyclops.streams.operators.LimitWhileTimeOperator;
import com.aol.cyclops.streams.operators.MultiCollectOperator;
import com.aol.cyclops.streams.operators.MultiReduceOperator;
import com.aol.cyclops.streams.operators.OnePerOperator;
import com.aol.cyclops.streams.operators.RecoverOperator;
import com.aol.cyclops.streams.operators.SkipLastOperator;
import com.aol.cyclops.streams.operators.SkipWhileOperator;
import com.aol.cyclops.streams.operators.SkipWhileTimeOperator;
import com.aol.cyclops.streams.operators.WindowByTimeAndSizeOperator;
import com.aol.cyclops.streams.operators.WindowStatefullyWhileOperator;
import com.aol.cyclops.streams.operators.WindowWhileOperator;
@UtilityClass
public class StreamUtils{
public final static Optional> streamToOptional(Stream stream){
List collected = stream.collect(Collectors.toList());
if(collected.size()==0)
return Optional.empty();
return Optional.of(collected);
}
public final static Stream optionalToStream(Optional optional){
if(optional.isPresent())
return Stream.of(optional.get());
return Stream.of();
}
public final static CompletableFuture> streamToCompletableFuture(Stream stream){
return CompletableFuture.completedFuture(stream.collect(Collectors.toList()));
}
public final static Stream completableFutureToStream(CompletableFuture future){
return Stream.of(future.join());
}
/**
* Split at supplied location
*
* {@code
* SequenceM.of(1,2,3).splitAt(1)
*
* //SequenceM[1], SequenceM[2,3]
* }
*
*
*/
public final static Tuple2,Stream> splitAt(Stream stream,int where){
Tuple2,Stream> Tuple2 = duplicate(stream);
return new Tuple2(Tuple2.v1.limit(where),Tuple2.v2.skip(where));
}
/**
* Split stream at point where predicate no longer holds
*
* {@code
* SequenceM.of(1, 2, 3, 4, 5, 6).splitBy(i->i<4)
*
* //SequenceM[1,2,3] SequenceM[4,5,6]
* }
*
*/
public final static Tuple2,Stream> splitBy(Stream stream,Predicate splitter){
Tuple2,Stream> Tuple2 = duplicate(stream);
return new Tuple2(limitWhile(Tuple2.v1,splitter),skipWhile(Tuple2.v2,splitter));
}
/**
* Partition a Stream into two one a per element basis, based on predicate's boolean value
*
* {@code
* SequenceM.of(1, 2, 3, 4, 5, 6).partition(i -> i % 2 != 0)
*
* //SequenceM[1,3,5], SequenceM[2,4,6]
* }
*
*
*/
public final static Tuple2,Stream> partition(Stream stream,Predicate splitter){
Tuple2,Stream> Tuple2 = duplicate(stream);
return new Tuple2(Tuple2.v1.filter(splitter),Tuple2.v2.filter(splitter.negate()));
}
/**
* Duplicate a Stream, buffers intermediate values, leaders may change positions so a limit
* can be safely applied to the leading stream. Not thread-safe.
*
* {@code
* Tuple2, SequenceM> copies =of(1,2,3,4,5,6).duplicate();
assertTrue(copies.v1.anyMatch(i->i==2));
assertTrue(copies.v2.anyMatch(i->i==2));
*
* }
*
*
* @return duplicated stream
*/
public final static Tuple2,Stream> duplicate(Stream stream){
Tuple2,Iterator> Tuple2 = StreamUtils.toBufferingDuplicator(stream.iterator());
return new Tuple2(StreamUtils.stream(Tuple2.v1()),StreamUtils.stream(Tuple2.v2()));
}
private final static Tuple2,Stream> duplicatePos(Stream stream,int pos){
Tuple2,Iterator> Tuple2 = StreamUtils.toBufferingDuplicator(stream.iterator(),pos);
return new Tuple2(StreamUtils.stream(Tuple2.v1()),StreamUtils.stream(Tuple2.v2()));
}
/**
* Triplicates a Stream
* Buffers intermediate values, leaders may change positions so a limit
* can be safely applied to the leading stream. Not thread-safe.
*
* {@code
* Tuple3>,SequenceM>,SequenceM>> Tuple3 = sequence.triplicate();
* }
*
*/
@SuppressWarnings("unchecked")
public final static Tuple3,Stream,Stream> triplicate(Stream stream){
Stream> its = StreamUtils.toBufferingCopier(stream.iterator(),3)
.stream()
.map(it -> StreamUtils.stream(it));
Iterator> it = its.iterator();
return new Tuple3(it.next(),it.next(),it.next());
}
/**
* Makes four copies of a Stream
* Buffers intermediate values, leaders may change positions so a limit
* can be safely applied to the leading stream. Not thread-safe.
*
*
* {@code
*
* Tuple4>,SequenceM>,SequenceM>,SequenceM>> quad = sequence.quadruplicate();
* }
*
* @return
*/
@SuppressWarnings("unchecked")
public final static Tuple4,Stream,Stream,Stream> quadruplicate(Stream stream){
Stream> its = StreamUtils.toBufferingCopier(stream.iterator(),4)
.stream()
.map(it -> StreamUtils.stream(it));
Iterator> it = its.iterator();
return new Tuple4(it.next(),it.next(),it.next(),it.next());
}
/**
* Append Stream to this SequenceM
*
*
* {@code
* List result = of(1,2,3).appendStream(of(100,200,300))
.map(it ->it+"!!")
.collect(Collectors.toList());
assertThat(result,equalTo(Arrays.asList("1!!","2!!","3!!","100!!","200!!","300!!")));
* }
*
*
* @param stream to append
* @return SequenceM with Stream appended
*/
public static final Stream appendStream(Stream stream1,Stream append) {
return Stream.concat(stream1, append);
}
/**
* Prepend Stream to this SequenceM
*
*
* {@code
* List result = of(1,2,3).prependStream(of(100,200,300))
.map(it ->it+"!!").collect(Collectors.toList());
assertThat(result,equalTo(Arrays.asList("100!!","200!!","300!!","1!!","2!!","3!!")));
*
* }
*
*
* @param stream to Prepend
* @return SequenceM with Stream prepended
*/
public static final Stream prependStream(Stream stream1,Stream prepend) {
return Stream.concat(prepend,stream1);
}
/**
* Append values to the end of this SequenceM
*
* {@code
* List result = of(1,2,3).append(100,200,300)
.map(it ->it+"!!")
.collect(Collectors.toList());
assertThat(result,equalTo(Arrays.asList("1!!","2!!","3!!","100!!","200!!","300!!")));
* }
*
* @param values to append
* @return SequenceM with appended values
*/
public static final Stream append(Stream stream,T... values) {
return appendStream(stream,Stream.of(values));
}
/**
* Prepend given values to the start of the Stream
*
* {@code
* List result = of(1,2,3).prepend(100,200,300)
.map(it ->it+"!!").collect(Collectors.toList());
assertThat(result,equalTo(Arrays.asList("100!!","200!!","300!!","1!!","2!!","3!!")));
* }
* @param values to prepend
* @return SequenceM with values prepended
*/
public static final Stream prepend(Stream stream,T... values) {
return appendStream(Stream.of(values),stream);
}
/**
* Insert data into a stream at given position
*
* {@code
* List result = of(1,2,3).insertAt(1,100,200,300)
.map(it ->it+"!!").collect(Collectors.toList());
assertThat(result,equalTo(Arrays.asList("1!!","100!!","200!!","300!!","2!!","3!!")));
*
* }
*
* @param pos to insert data at
* @param values to insert
* @return Stream with new data inserted
*/
public static final Stream insertAt(Stream stream,int pos, T... values) {
Tuple2,Stream> Tuple2 = duplicatePos(stream,pos);
return appendStream(append(Tuple2.v1.limit(pos),values),Tuple2.v2.skip(pos));
}
/**
* Delete elements between given indexes in a Stream
*
* {@code
* List result = of(1,2,3,4,5,6).deleteBetween(2,4)
.map(it ->it+"!!").collect(Collectors.toList());
assertThat(result,equalTo(Arrays.asList("1!!","2!!","5!!","6!!")));
* }
*
* @param start index
* @param end index
* @return Stream with elements removed
*/
public static final Stream deleteBetween(Stream stream,int start,int end) {
Tuple2,Stream> Tuple2 = duplicatePos(stream,start);
return appendStream(Tuple2.v1.limit(start),Tuple2.v2.skip(end));
}
/**
* Insert a Stream into the middle of this stream at the specified position
*
* {@code
* List result = of(1,2,3).insertStreamAt(1,of(100,200,300))
.map(it ->it+"!!").collect(Collectors.toList());
assertThat(result,equalTo(Arrays.asList("1!!","100!!","200!!","300!!","2!!","3!!")));
* }
*
* @param pos to insert Stream at
* @param stream to insert
* @return newly conjoined SequenceM
*/
public static final Stream insertStreamAt(Stream stream1,int pos, Stream insert) {
Tuple2,Stream> Tuple2 = duplicatePos(stream1,pos);
return appendStream(appendStream(Tuple2.v1.limit(pos),insert),Tuple2.v2.skip(pos));
}
/**
* Convert to a Stream with the result of a reduction operation repeated
* specified times
*
*
* {@code
* List list = StreamUtils.cycle(Stream.of(1,2,2),Reducers.toCountInt(),3)
* .
* .collect(Collectors.toList());
* //is asList(3,3,3);
* }
*
*
* @param m
* Monoid to be used in reduction
* @param times
* Number of times value should be repeated
* @return Stream with reduced values repeated
*/
public final static Stream cycle(Stream stream,Monoid m, int times) {
return StreamUtils.cycle(times,AsStreamable.fromObject(m.reduce(stream)));
}
/**
* extract head and tail together
*
*
* {@code
* Stream helloWorld = Stream.of("hello","world","last");
HeadAndTail headAndTail = StreamUtils.headAndTail(helloWorld);
String head = headAndTail.head();
assertThat(head,equalTo("hello"));
SequenceM tail = headAndTail.tail();
assertThat(tail.headAndTail().head(),equalTo("world"));
* }
*
*
* @return
*/
public final static HeadAndTail headAndTail(Stream stream){
Iterator it = stream.iterator();
return new HeadAndTail(it.next(),sequenceM(stream(it),Optional.empty()));
}
/**
*
* {@code
* Stream helloWorld = Stream.of();
Optional> headAndTail = StreamUtils.headAndTailOptional(helloWorld);
assertTrue(!headAndTail.isPresent());
* }
*
* @param stream to extract head and tail from
* @return
*/
public final static Optional> headAndTailOptional(Stream stream){
Iterator it = stream.iterator();
if(!it.hasNext())
return Optional.empty();
return Optional.of(new HeadAndTail(it.next(),sequenceM(stream(it),Optional.empty())));
}
/**
* skip elements in Stream until Predicate holds true
*
* {@code StreamUtils.skipUntil(Stream.of(4,3,6,7),i->i==6).collect(Collectors.toList())
* // [6,7]
* }
* @param stream Stream to skip elements from
* @param predicate to apply
* @return Stream with elements skipped
*/
public static Stream skipUntil(Stream stream,Predicate super U> predicate){
return skipWhile(stream,predicate.negate());
}
public static Stream skipLast(Stream stream,int num){
return new SkipLastOperator<>(stream,num).skipLast();
}
public static Stream limitLast(Stream stream,int num){
return new LimitLastOperator<>(stream,num).limitLast();
}
public static Stream recover(Stream stream,Function fn){
return new RecoverOperator<>(stream,Throwable.class).recover(fn);
}
public static Stream recover(Stream stream,Class type,
Function fn){
return new RecoverOperator(stream,(Class)type)
.recover((Function)fn);
}
/**
* skip elements in a Stream while Predicate holds true
*
*
*
* {@code StreamUtils.skipWhile(Stream.of(4,3,6,7).sorted(),i->i<6).collect(Collectors.toList())
* // [6,7]
* }
* @param stream
* @param predicate
* @return
*/
public static Stream skipWhile(Stream stream,Predicate super U> predicate){
return new SkipWhileOperator(stream).skipWhile(predicate);
}
public static Stream limit(Stream stream,long time, TimeUnit unit){
return new LimitWhileTimeOperator(stream).limitWhile(time,unit);
}
public static Stream skip(Stream stream,long time, TimeUnit unit){
return new SkipWhileTimeOperator(stream).skipWhile(time,unit);
}
/**
* Take elements from a stream while the predicates hold
*
* {@code StreamUtils.limitWhile(Stream.of(4,3,6,7).sorted(),i->i<6).collect(Collectors.toList());
* //[4,3]
* }
*
* @param stream
* @param predicate
* @return
*/
public static Stream limitWhile(Stream stream,Predicate super U> predicate){
return new LimitWhileOperator(stream).limitWhile(predicate);
}
/**
* Take elements from a Stream until the predicate holds
*
* {@code StreamUtils.limitUntil(Stream.of(4,3,6,7),i->i==6).collect(Collectors.toList());
* //[4,3]
* }
*
* @param stream
* @param predicate
* @return
*/
public static Stream limitUntil(Stream stream,Predicate super U> predicate){
return limitWhile(stream,predicate.negate());
}
/**
* Reverse a Stream
*
*
* {@code
* assertThat(StreamUtils.reverse(Stream.of(1,2,3)).collect(Collectors.toList())
,equalTo(Arrays.asList(3,2,1)));
* }
*
*
* @param stream Stream to reverse
* @return Reversed stream
*/
public static Stream reverse(Stream stream){
return reversedStream(stream.collect(Collectors.toList()));
}
/**
* Create a reversed Stream from a List
*
* {@code
* StreamUtils.reversedStream(asList(1,2,3))
.map(i->i*100)
.forEach(System.out::println);
assertThat(StreamUtils.reversedStream(Arrays.asList(1,2,3)).collect(Collectors.toList())
,equalTo(Arrays.asList(3,2,1)));
*
* }
*
*
* @param list List to create a reversed Stream from
* @return Reversed Stream
*/
public static Stream reversedStream(List list){
return new ReversedIterator<>(list).stream();
}
/**
* Create a new Stream that infiniteable cycles the provided Stream
*
*
* {@code
* assertThat(StreamUtils.cycle(Stream.of(1,2,3))
* .limit(6)
* .collect(Collectors.toList()),
* equalTo(Arrays.asList(1,2,3,1,2,3)));
}
*
* @param s Stream to cycle
* @return New cycling stream
*/
public static Stream cycle(Stream s){
return cycle(AsStreamable.fromStream(s));
}
/**
* Create a Stream that infiniteable cycles the provided Streamable
* @param s Streamable to cycle
* @return New cycling stream
*/
public static Stream cycle(Streamable s){
return Stream.iterate(s.stream(),s1-> s.stream()).flatMap(Function.identity());
}
/**
* Create a Stream that finitely cycles the provided Streamable, provided number of times
*
*
* {@code
* assertThat(StreamUtils.cycle(3,Streamable.of(1,2,2))
.collect(Collectors.toList()),
equalTo(Arrays.asList(1,2,2,1,2,2,1,2,2)));
* }
*
* @param s Streamable to cycle
* @return New cycling stream
*/
public static Stream cycle(int times,Streamable s){
return Stream.iterate(s.stream(),s1-> s.stream()).limit(times).flatMap(Function.identity());
}
/**
* Create a stream from an iterable
*
* {@code
* assertThat(StreamUtils.stream(Arrays.asList(1,2,3))
* .collect(Collectors.toList()),
* equalTo(Arrays.asList(1,2,3)));
*
* }
*
* @param it Iterable to convert to a Stream
* @return Stream from iterable
*/
public static Stream stream(Iterable it){
return StreamSupport.stream(it.spliterator(),
false);
}
public static Stream stream(Spliterator it){
return StreamSupport.stream(it,
false);
}
/**
* Create a stream from an iterator
*
* {@code
* assertThat(StreamUtils.stream(Arrays.asList(1,2,3).iterator())
* .collect(Collectors.toList()),
* equalTo(Arrays.asList(1,2,3)));
* }
*
* @param it Iterator to convert to a Stream
* @return Stream from iterator
*/
public static Stream stream(Iterator it){
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.ORDERED),
false);
}
/**
* Concat an Object and a Stream
* If the Object is a Stream, Streamable or Iterable will be converted (or left) in Stream form and concatonated
* Otherwise a new Stream.of(o) is created
*
* @param o Object to concat
* @param stream Stream to concat
* @return Concatonated Stream
*/
public static Stream concat(Object o, Stream stream){
Stream first = null;
if(o instanceof Stream){
first = (Stream)o;
}else if(o instanceof Iterable){
first = stream( (Iterable)o);
}
else if(o instanceof Streamable){
first = ((Streamable)o).stream();
}
else{
first = Stream.of((U)o);
}
return Stream.concat(first, stream);
}
/**
* Create a stream from a map
*
* {@code
* Map map = new HashMap<>();
map.put("hello","world");
assertThat(StreamUtils.stream(map).collect(Collectors.toList()),equalTo(Arrays.asList(new AbstractMap.SimpleEntry("hello","world"))));
* }
*
*
* @param it Iterator to convert to a Stream
* @return Stream from a map
*/
public final static Stream> stream(Map it){
return it.entrySet().stream();
}
public final static FutureOperations futureOperations(Stream stream,Executor exec){
return new FutureOperationsImpl(exec,sequenceM(stream,Optional.empty()));
}
public final static T firstValue(Stream stream){
return stream.findAny().get();
}
/**
* Simultaneously reduce a stream with multiple reducers
*
* {@code
*
* Monoid sum = Monoid.of(0,(a,b)->a+b);
Monoid mult = Monoid.of(1,(a,b)->a*b);
val result = StreamUtils.reduce(Stream.of(1,2,3,4),Arrays.asList(sum,mult));
assertThat(result,equalTo(Arrays.asList(10,24)));
}
*
* @param stream Stream to reduce
* @param reducers Reducers to reduce Stream
* @return Reduced Stream values as List entries
*/
@SuppressWarnings({"rawtypes","unchecked"})
public static List reduce(Stream stream,Iterable> reducers){
return new MultiReduceOperator(stream).reduce(reducers);
}
/**
* Simultanously reduce a stream with multiple reducers
*
*
* {@code
* Monoid concat = Monoid.of("",(a,b)->a+b);
Monoid join = Monoid.of("",(a,b)->a+","+b);
assertThat(StreamUtils.reduce(Stream.of("hello", "world", "woo!"),Stream.of(concat,join))
,equalTo(Arrays.asList("helloworldwoo!",",hello,world,woo!")));
* }
*
*
* @param stream Stream to reduce
* @param reducers Reducers to reduce Stream
* @return Reduced Stream values as List entries
*/
@SuppressWarnings({"rawtypes","unchecked"})
public static List reduce(Stream stream,Stream> reducers){
return (List)reduce(stream, (List)reducers.collect(Collectors.toList()));
}
/**
* Apply multiple Collectors, simultaneously to a Stream
*
* {@code
* List result = StreamUtils.collect(Stream.of(1,2,3),
Stream.of(Collectors.toList(),
Collectors.summingInt(Integer::intValue),
Collectors.averagingInt(Integer::intValue)));
assertThat(result.get(0),equalTo(Arrays.asList(1,2,3)));
assertThat(result.get(1),equalTo(6));
assertThat(result.get(2),equalTo(2.0));
* }
*
* @param stream Stream to collect
* @param collectors Collectors to apply
* @return Result as a list
*/
public static List collect(Stream stream, Stream collectors){
return collect(stream, AsStreamable.fromStream(collectors));
}
/**
* Apply multiple Collectors, simultaneously to a Stream
*
* {@code
* List result = StreamUtils.collect(Stream.of(1,2,3),
Arrays.asList(Collectors.toList(),
Collectors.summingInt(Integer::intValue),
Collectors.averagingInt(Integer::intValue)));
assertThat(result.get(0),equalTo(Arrays.asList(1,2,3)));
assertThat(result.get(1),equalTo(6));
assertThat(result.get(2),equalTo(2.0));
* }
*
* @param stream Stream to collect
* @param collectors Collectors to apply
* @return Result as a list
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static List collect(Stream stream, Iterable collectors){
return collect(stream, AsStreamable.fromIterable(collectors));
}
/**
* Apply multiple Collectors, simultaneously to a Stream
*
* {@code
* List result = StreamUtils.collect(Stream.of(1,2,3),
Streamable.of(Collectors.toList(),
Collectors.summingInt(Integer::intValue),
Collectors.averagingInt(Integer::intValue)));
assertThat(result.get(0),equalTo(Arrays.asList(1,2,3)));
assertThat(result.get(1),equalTo(6));
assertThat(result.get(2),equalTo(2.0));
*
* }
*
* @param stream Stream to collect
* @param collectors Collectors to apply
* @return Result as a list
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static List collect(Stream stream, Streamable collectors){
return new MultiCollectOperator(stream).collect(collectors);
}
/**
* Repeat in a Stream while specified predicate holds
*
* {@code
* int count =0;
*
assertThat(StreamUtils.cycleWhile(Stream.of(1,2,2)
,next -> count++<6 )
.collect(Collectors.toList()),equalTo(Arrays.asList(1,2,2,1,2,2)));
* }
*
* @param predicate
* repeat while true
* @return Repeating Stream
*/
public final static Stream cycleWhile(Stream stream,Predicate super T> predicate) {
return StreamUtils.limitWhile(StreamUtils.cycle(stream),predicate);
}
/**
* Repeat in a Stream until specified predicate holds
*
*
* {@code
* count =0;
assertThat(StreamUtils.cycleUntil(Stream.of(1,2,2,3)
,next -> count++>10 )
.collect(Collectors.toList()),equalTo(Arrays.asList(1, 2, 2, 3, 1, 2, 2, 3, 1, 2, 2)));
* }
*
* @param predicate
* repeat while true
* @return Repeating Stream
*/
public final static Stream cycleUntil(Stream stream,Predicate super T> predicate) {
return StreamUtils.limitUntil(StreamUtils.cycle(stream),predicate);
}
/**
* Generic zip function. E.g. Zipping a Stream and a Sequence
*
*
* {@code
* Stream> zipped = StreamUtils.zip(Stream.of(1,2,3)
,SequenceM.of(2,3,4),
(a,b) -> Arrays.asList(a,b));
List zip = zipped.collect(Collectors.toList()).get(1);
assertThat(zip.get(0),equalTo(2));
assertThat(zip.get(1),equalTo(3));
* }
*
* @param second
* Monad to zip with
* @param zipper
* Zipping function
* @return Stream zipping two Monads
*/
public final static Stream zipSequence(Stream stream,Stream extends S> second,
BiFunction super T, ? super S, ? extends R> zipper) {
Iterator left = stream.iterator();
Iterator extends S> right = second.iterator();
return StreamUtils.stream(new Iterator(){
@Override
public boolean hasNext() {
return left.hasNext() && right.hasNext();
}
@Override
public R next() {
return zipper.apply(left.next(), right.next());
}
});
}
/**
* Generic zip function. E.g. Zipping a Stream and an Optional
*
*
* {@code
* Stream> zipped = StreamUtils.zip(Stream.of(1,2,3)
,anyM(Optional.of(2)),
(a,b) -> Arrays.asList(a,b));
List zip = zipped.collect(Collectors.toList()).get(0);
assertThat(zip.get(0),equalTo(1));
assertThat(zip.get(1),equalTo(2));
*
* }
*
*/
public final static Stream zipAnyM(Stream stream,AnyM extends S> second,
BiFunction super T, ? super S, ? extends R> zipper) {
return zipSequence(stream,second.toSequence(), zipper);
}
/**
* Zip this Monad with a Stream
*
{@code
Stream> zipped = StreamUtils.zipStream(Stream.of(1,2,3)
,Stream.of(2,3,4),
(a,b) -> Arrays.asList(a,b));
List zip = zipped.collect(Collectors.toList()).get(1);
assertThat(zip.get(0),equalTo(2));
assertThat(zip.get(1),equalTo(3));
}
*
* @param second
* Stream to zip with
* @param zipper
* Zip funciton
* @return This monad zipped with a Stream
*/
public final static Stream zipStream(Stream stream,BaseStream extends S,? extends BaseStream extends S,?>> second,
BiFunction super T, ? super S, ? extends R> zipper) {
Iterator left = stream.iterator();
Iterator extends S> right = second.iterator();
return StreamUtils.stream(new Iterator(){
@Override
public boolean hasNext() {
return left.hasNext() && right.hasNext();
}
@Override
public R next() {
return zipper.apply(left.next(), right.next());
}
});
}
/**
* Create a sliding view over this Stream
*
* {@code
* List> list = StreamUtils.sliding(Stream.of(1,2,3,4,5,6)
,2,1)
.collect(Collectors.toList());
assertThat(list.get(0),hasItems(1,2));
assertThat(list.get(1),hasItems(2,3));
* }
*
* @param windowSize
* Size of sliding window
* @return Stream with sliding view over monad
*/
public final static Stream> sliding(Stream stream,int windowSize,int increment) {
Iterator it = stream.iterator();
Mutable> list = Mutable.of(ConsPStack.empty());
return StreamUtils.stream(new Iterator>(){
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public List next() {
for(int i=0;i0;i++)
list.mutate(var -> var.minus(0));
for (int i = 0; list.get().size() < windowSize && it.hasNext(); i++) {
if(it.hasNext()){
list.mutate(var -> var.plus(Math.max(0,var.size()),it.next()));
}
}
return list.get();
}
});
}
/**
* Create a sliding view over this Stream
*
* {@code
* List> list = StreamUtils.sliding(Stream.of(1,2,3,4,5,6)
,2,1)
.collect(Collectors.toList());
assertThat(list.get(0),hasItems(1,2));
assertThat(list.get(1),hasItems(2,3));
* }
*
* @param windowSize
* Size of sliding window
* @return Stream with sliding view over monad
*/
public final static Stream> window(Stream stream,int windowSize,int increment) {
Iterator it = stream.iterator();
Mutable> list = Mutable.of(ConsPStack.empty());
return StreamUtils.stream(new Iterator>(){
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public Streamable next() {
for(int i=0;i0;i++)
list.mutate(var -> var.minus(0));
for (int i = 0; list.get().size() < windowSize && it.hasNext(); i++) {
if(it.hasNext()){
list.mutate(var -> var.plus(Math.max(0,var.size()),it.next()));
}
}
return Streamable.fromIterable(list.get());
}
});
}
/**
* Create a sliding view over this Stream
*
* {@code
* List> list = StreamUtils.sliding(Stream.of(1,2,3,4,5,6)
,2)
.collect(Collectors.toList());
assertThat(list.get(0),hasItems(1,2));
assertThat(list.get(1),hasItems(2,3));
* }
*
*
* @param stream Stream to create sliding view on
* @param windowSize size of window
* @return
*/
public final static Stream> sliding(Stream stream,int windowSize) {
return sliding(stream,windowSize,1);
}
/**
* Group elements in a Monad into a Stream
*
{@code
* List> list = StreamUtils.grouped(Stream.of(1,2,3,4,5,6)
,3)
.collect(Collectors.toList());
assertThat(list.get(0),hasItems(1,2,3));
assertThat(list.get(1),hasItems(4,5,6));
}
*
* @param groupSize
* Size of each Group
* @return Stream with elements grouped by size
*/
public final static Stream> batchBySize(Stream stream,int groupSize) {
return new BatchBySizeOperator>(stream).batchBySize(groupSize);
}
public final static> Stream batchBySize(Stream stream,int groupSize, Supplier factory) {
return new BatchBySizeOperator(stream,factory).batchBySize(groupSize);
}
public final static Streamable