package com.gx.obe.bind.recursion; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; public class Recursions<T> { private Function<T, Stream<T>> toStreamFun; public static <T> Recursions<T> array(Function<T, T[]> toArrayFun) { return new Recursions<>(toArrayFun.andThen(t -> Optional.ofNullable(t).map(Stream::of).orElse(null))); } public static <T> Recursions<T> list(Function<T, List<T>> toListFun) { return new Recursions<>(toListFun.andThen(t -> Optional.ofNullable(t).map(List::stream).orElse(null))); } public static <T> Recursions<T> stream(Function<T, Stream<T>> toStreamFun) { return new Recursions<>(toStreamFun); } public Recursions(Function<T, Stream<T>> toStreamFun) { this.toStreamFun = toStreamFun; } public RStream<T> toStream(T obj) { return toStream(Stream.of(obj)); } public RStream<T> toStream(T[] array) { return toStream(Stream.of(array)); } public RStream<T> toStream(List<T> stream) { return toStream(stream.stream()); } public RStream<T> toStream(Stream<T> stream) { return new RStream<T>() { public void forEach(Consumer<T> action) { new ForEachRecursion(action).exe(stream); } public void forEach(TreeForEach<T> treeForEach) { new TreeForEachRecursion(treeForEach).exe(stream); } public void forEach(BiConsumer<List<Integer>, T> indexConsumer) { new IndexForEachRecursion(indexConsumer).exe(stream); } public Optional<T> findAny(Predicate<T> predicate) { Data data = new Data(); new AnyMatchRecursion(t -> { boolean test = predicate.test(t); if (test) data.t = t; return test; }).exe(stream); return Optional.ofNullable(data.t); } public List<T> filter(Predicate<T> predicate) { List<T> list = new ArrayList<>(); new ForEachRecursion(t -> { if (predicate.test(t)) list.add(t); }).exe(stream); return list; } }; } private class AnyMatchRecursion { private Predicate<T> predicate; public AnyMatchRecursion(Predicate<T> predicate) { this.predicate = predicate; } private boolean exe(Stream<T> stream) { return stream.anyMatch(t -> { if (predicate.test(t)) return true; return Optional.ofNullable(t).map(toStreamFun).map(this::exe).orElse(false); }); } } private class ForEachRecursion { private Consumer<T> consumer; public ForEachRecursion(Consumer<T> consumer) { this.consumer = consumer; } private void exe(Stream<T> stream) { stream.forEach(t -> { consumer.accept(t); Optional.ofNullable(t).map(toStreamFun).ifPresent(this::exe); }); } } private class TreeForEachRecursion { private TreeForEach<T> treeForEach; public TreeForEachRecursion(TreeForEach<T> treeForEach) { this.treeForEach = treeForEach; } private void exe(Stream<T> stream) { recursion(stream.iterator(), true); } private void recursion(Iterator<T> iterator, boolean root) { iterator.forEachRemaining(t -> { Iterator<T> citerator = Optional.of(t).map(toStreamFun).map(Stream::iterator).orElse(null); boolean leaf = citerator == null || !citerator.hasNext(); treeForEach.action(root, leaf, t); if (!leaf) recursion(citerator, false); }); } } private class IndexForEachRecursion { private BiConsumer<List<Integer>, T> indexConsumer; public IndexForEachRecursion(BiConsumer<List<Integer>, T> indexConsumer) { this.indexConsumer = indexConsumer; } private void exe(Stream<T> stream) { recursion(stream, new ArrayList<>()); } private void recursion(Stream<T> stream, List<Integer> pIndex) { AtomicInteger i = new AtomicInteger(1); stream.forEach(t -> { List<Integer> index = new ArrayList<>(pIndex); index.add(i.getAndIncrement()); indexConsumer.accept(index, t); Optional.ofNullable(t).map(toStreamFun).ifPresent(s -> recursion(s, index)); }); } } private class Data { private T t; } }