public final static <T,C extends Comparable<? super C>> Optional<T> minBy(Stream<T> stream,Function<T,C> f){ Optional<Pair<C,T>> o = stream.map(in->new Pair<C,T>(f.apply(in),in)).min(Comparator.comparing(n->n._1(),Comparator.naturalOrder())); return o.map(p->p._2()); } public final static<T> Optional<T> min(Stream<T> stream,Comparator<? super T> comparator){
/** * zip 3 Streams into one * <pre> * {@code * List<Triple<Integer,Integer,Character>> list = of(1,2,3,4,5,6).zip3(of(100,200,300,400),of('a','b','c')) .collect(Collectors.toList()); * * //[[1,100,'a'],[2,200,'b'],[3,300,'c']] * } * *</pre> */ public final <S,U> SequenceM<Triple<T,S,U>> zip3(Stream<? extends S> second,Stream<? extends U> third){ return zip(second).zip(third).map(p -> new Triple(p._1()._1(),p._1()._2(),p._2())); } /**
/** * Zip 2 streams into one * * <pre> * {@code * List<Pair<Integer, String>> list = of(1, 2).zip(of("a", "b", "c", "d")).toList(); // [[1,"a"],[2,"b"]] } * </pre> * */ public final <S> SequenceM<Pair<T,S>> zip(Stream<? extends S> second){ return zipStream(second,(a,b)->new Pair<>(a,b)); } /**
/** * Filter current monad by each element in supplied Monad * * e.g. * * <pre>{@code * Simplex<Stream<Integer>> applied = monad(Stream.of(1,2,3)) * .filterM(monad(Streamable.of( (Integer a)->a>5 ,(Integer a) -> a<3))) * .simplex(); * * //results in Stream.of(Stream.of(1),Stream.of(2),Stream.of(()) * }</pre> * * @param fn * @return */ default <NT,R> Monad<NT,R> simpleFilter(Monad<?,Predicate<? super T>> fn){ return (Monad)this.bind(v-> fn.map(innerFn -> new Pair(v,innerFn.test(v))) .filter(p->(boolean)p._2()) .map(Pair::_1)) .map(m -> ((Monad) m).unwrap()); // filterM((a: Int) => List(a > 2, a % 2 == 0), List(1, 2, 3), ListMonad), //List(List(3), Nil, List(2, 3), List(2), List(3), // Nil, List(2, 3), List(2)) } /**
/** * Split a Stream at it's head (similar to headAndTail) * <pre> * {@code * SequenceM.of(1,2,3).splitAtHead() * * //Optional[1], SequenceM[2,3] * } * * </pre> * */ @SuppressWarnings({ "unchecked", "rawtypes" }) public final Pair<Optional<T>,SequenceM<T>> splitAtHead(){ Pair<SequenceM<T>,SequenceM<T>> pair = splitAt(1); return new Pair(pair.v1.unwrapOptional() .flatMap( l-> l.size()>0 ? Optional.of(l.get(0)) : Optional.empty() ) ,pair.v2); } /**
/** * zip 4 Streams into 1 * * <pre> * {@code * List<Quadruple<Integer,Integer,Character,String>> list = of(1,2,3,4,5,6).zip4(of(100,200,300,400),of('a','b','c'),of("hello","world")) .collect(Collectors.toList()); * } * //[[1,100,'a',"hello"],[2,200,'b',"world"]] * </pre> */ public final <T2,T3,T4> SequenceM<Quadruple<T,T2,T3,T4>> zip4(Stream<T2> second,Stream<T3> third,Stream<T4> fourth){ return zip3(second,third).zip(fourth).map(t -> new Quadruple(t._1()._1(), t._1()._2(),t._1()._3(),t._2())); } /**
public final static <T,C extends Comparable<? super C>> Optional<T> maxBy(Stream<T> stream,Function<T,C> f){ Optional<Pair<C,T>> o = stream.map(in->new Pair<C,T>(f.apply(in),in)).max(Comparator.comparing(n->n._1(),Comparator.naturalOrder())); return o.map(p->p._2()); } public final static<T> Optional<T> max(Stream<T> stream,Comparator<? super T> comparator){
/** * Add an index to the current Stream * * <pre> * {@code * assertEquals(asList(new Pair("a", 0L), new Pair("b", 1L)), of("a", "b").zipWithIndex().toList()); * } * </pre> */ public final SequenceM<Pair<T,Long>> zipWithIndex(){ return zipStream(LongStream.iterate(0, i->i+1),(a,b)->new Pair<>(a,b)); } /**
public static final <A> Pair<Iterator<A>,Iterator<A>> toBufferingDuplicator(Iterator<A> iterator,long pos) { LinkedList<A> bufferTo = new LinkedList<A>(); LinkedList<A> bufferFrom = new LinkedList<A>(); return new Pair(new DuplicatingIterator(bufferTo,bufferFrom,iterator,Long.MAX_VALUE,0), new DuplicatingIterator(bufferFrom,bufferTo,iterator,pos,0)); } public static final <A> List<Iterator<A>> toBufferingCopier(Iterator<A> iterator,int copies) {
/** * Duplicate a Stream, buffers intermediate values, leaders may change positions so a limit * can be safely applied to the leading stream. Not thread-safe. * <pre> * {@code * Pair<SequenceM<Integer>, SequenceM<Integer>> copies =of(1,2,3,4,5,6).duplicate(); assertTrue(copies.v1.anyMatch(i->i==2)); assertTrue(copies.v2.anyMatch(i->i==2)); * * } * </pre> * * @return duplicated stream */ public final Pair<SequenceM<T>,SequenceM<T>> duplicate(){ Pair<Iterator<T>,Iterator<T>> pair = StreamUtils.toBufferingDuplicator(monad.iterator()); return new Pair(new SequenceM(StreamUtils.stream(pair._1())),new SequenceM(StreamUtils.stream(pair._2()))); } private final Pair<SequenceM<T>,SequenceM<T>> duplicatePos(int pos){
/** * Partition a Stream into two one a per element basis, based on predicate's boolean value * <pre> * {@code * SequenceM.of(1, 2, 3, 4, 5, 6).partition(i -> i % 2 != 0) * * //SequenceM[1,3,5], SequenceM[2,4,6] * } * * </pre> */ public final Pair<SequenceM<T>,SequenceM<T>> partition(Predicate<T> splitter){ Pair<SequenceM<T>,SequenceM<T>> pair = duplicate(); return new Pair(pair.v1.filter(splitter),pair.v2.filter(splitter.negate())); }
/** * Split stream at point where predicate no longer holds * <pre> * {@code * SequenceM.of(1, 2, 3, 4, 5, 6).splitBy(i->i<4) * * //SequenceM[1,2,3] SequenceM[4,5,6] * } * </pre> */ public final Pair<SequenceM<T>,SequenceM<T>> splitBy(Predicate<T> splitter){ Pair<SequenceM<T>,SequenceM<T>> pair = duplicate(); return new Pair(pair.v1.limitWhile(splitter),pair.v2.skipWhile(splitter)); } /**
/** * Split at supplied location * <pre> * {@code * SequenceM.of(1,2,3).splitAt(1) * * //SequenceM[1], SequenceM[2,3] * } * * </pre> */ public final Pair<SequenceM<T>,SequenceM<T>> splitAt(int where){ Pair<SequenceM<T>,SequenceM<T>> pair = duplicate(); return new Pair(pair.v1.limit(where),pair.v2.skip(where)); } /**
/** * Unzip a zipped Stream * * <pre> * {@code * unzip(SequenceM.of(new Pair(1, "a"), new Pair(2, "b"), new Pair(3, "c"))) * * // SequenceM[1,2,3], SequenceM[a,b,c] * } * * </pre> * */ public final static <T,U> Pair<SequenceM<T>,SequenceM<U>> unzip(SequenceM<Pair<T,U>> sequence){ Pair<SequenceM<Pair<T,U>>,SequenceM<Pair<T,U>>> pair = sequence.duplicate(); return new Pair(pair.v1.map(Pair::_1),pair.v2.map(Pair::_2)); } /**