Skip to content

Instantly share code, notes, and snippets.

@ritalin
Last active December 28, 2015 09:19
Show Gist options
  • Save ritalin/7478388 to your computer and use it in GitHub Desktop.
Save ritalin/7478388 to your computer and use it in GitHub Desktop.
Fluently collection operation class. Depends on Guava(http://code.google.com/p/guava-libraries/).
package sample;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.UnmodifiableIterator;
public class FluentCollection<T> implements Iterable<T> {
private FluentIterable<T> sources;
public static <TSource> FluentCollection<TSource> from(Iterable<TSource> sources) {
return new FluentCollection<TSource>(FluentIterable.from(sources));
}
public static <TSource> FluentCollection<TSource> from(TSource[] sources) {
return from(Arrays.asList(sources));
}
public static FluentCollection<Integer> generateInfinity(final int lower) {
return generateInfinity(lower, 1);
}
public static FluentCollection<Integer> generateInfinity(final int lower, final int skip) {
return iterateInternal(
lower, skip,
new Predicate<Integer>() {
@Override
public boolean apply(Integer current) {
return true;
}
}
);
}
private static FluentCollection<Integer> iterateInternal(final int lower, final int skip, final Predicate<Integer> rangePredicator) {
return from(new Iterable<Integer>() {
@Override
public Iterator<Integer> iterator() {
return new RangeIterator<Integer>(lower,
rangePredicator,
new Function<Integer, Integer>() {
@Override
public Integer apply(Integer current) {
return current + skip;
}
}
);
}
});
}
/**
* 両開空間で、範囲内の数値を列挙する
* @param lower
* @param upper
* @return
*/
public static FluentCollection<Integer> range(final int lower, int upper) {
return range(lower, upper, 1);
}
public static FluentCollection<Integer> range(final int lower, final int upper, final int skip) {
assert (lower <= upper);
return iterateInternal(
lower, skip,
new Predicate<Integer>() {
@Override
public boolean apply(Integer current) {
return current <= upper;
}
}
);
}
public static enum IterationStatus {
// 評価待ち
WAIT_EVALUATE,
// hasNext()実行待ち
WAIT_HAS_NEXT,
// next()実行待ち
WAIT_NEXT,
// 停止
TERMINATED
}
private static class RangeIterator<TNumber extends Number> extends UnmodifiableIterator<TNumber> {
private Predicate<TNumber> rangePredicator;
private Function<TNumber, TNumber> nextGenerator;
private TNumber current;
public RangeIterator(TNumber initial, Predicate<TNumber> rangePredicator, Function<TNumber, TNumber> nextGenerator) {
this.current = initial;
this.rangePredicator = rangePredicator;
this.nextGenerator = nextGenerator;
}
@Override
public boolean hasNext() {
return this.rangePredicator.apply(current);
}
@Override
public TNumber next() {
TNumber result = this.current;
this.current = this.nextGenerator.apply(result);
return result;
}
}
public static <TSource> FluentCollection<TSource> repeat(TSource source, int size) {
return from(FluentIterable.from(Arrays.asList(source)).cycle().limit(size));
}
public FluentCollection<T> append(T items) {
return this.append(Arrays.asList(items));
}
public FluentCollection<T> append(Iterable<? extends T> items) {
return from(Iterables.concat(this.sources, items));
}
public FluentCollection<T> prepend(Iterable<? extends T> items) {
return from(Iterables.concat(items, this.sources));
}
public <TResult> FluentCollection<TResult> map(Function<? super T, TResult> selector) {
return new FluentCollection<TResult>(this.sources.transform(selector));
}
public <TResult> FluentCollection<TResult> mapi(final Function3<Integer, ? super T, TResult> selector) {
return this.map(new Function<T, TResult>() {
private int index = 0;
@Override
public TResult apply(T source) {
return selector.apply(this.index++, source);
}
});
}
public <TResult> FluentCollection<TResult> fmap(Function<? super T, Iterable<TResult>> selector) {
return new FluentCollection<TResult>(this.sources.transformAndConcat(selector));
}
public FluentCollection<T> filter(Predicate<? super T> fn) {
return new FluentCollection<T>(this.sources.filter(fn));
}
public FluentCollection<List<T>> partition(int size) {
return new FluentCollection<List<T>>(FluentIterable.from(Iterables.partition(this.sources, size)));
}
public FluentCollection<T> skip(int i) {
return new FluentCollection<T>(this.sources.skip(i));
}
public FluentCollection<T> skipWhile(final Predicate<T> fn) {
return from(new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return new SkipWhileIterator<>(sources.iterator(), fn);
}
});
}
public static abstract class AbstractPredicateEvalIterator<TSource> extends UnmodifiableIterator<TSource> {
private Iterator<TSource> internalIterator;
private Predicate<TSource> predicator;
protected IterationStatus status = IterationStatus.WAIT_EVALUATE;
protected TSource current;
protected AbstractPredicateEvalIterator(Iterator<TSource> internalIterator, Predicate<TSource> predicator) {
this.internalIterator = internalIterator;
this.predicator = predicator;
}
@Override
public boolean hasNext() {
if (this.status == IterationStatus.TERMINATED) return false;
if (this.status == IterationStatus.WAIT_NEXT) return true;
return (this.status = this.evaluate(this.internalIterator, this.predicator)) != IterationStatus.TERMINATED;
}
abstract protected IterationStatus evaluate(Iterator<TSource> it, Predicate<TSource> fn);
@Override
public TSource next() {
if (this.status == IterationStatus.TERMINATED) {
throw new IllegalStateException("Sequence has been Already terminated.");
}
if (this.status == IterationStatus.WAIT_EVALUATE) {
throw new IllegalStateException("Sequence has not been yet evaluated.");
}
this.status = IterationStatus.WAIT_HAS_NEXT;
return this.current;
}
}
private static class SkipWhileIterator<TSource> extends AbstractPredicateEvalIterator<TSource> {
public SkipWhileIterator(Iterator<TSource> internalIterator, Predicate<TSource> predicator) {
super(internalIterator, predicator);
}
@Override
protected IterationStatus evaluate(Iterator<TSource> it, Predicate<TSource> fn) {
while(it.hasNext()) {
this.current = it.next();
if (this.status == IterationStatus.WAIT_EVALUATE) {
if (fn.apply(this.current)) continue;
}
return IterationStatus.WAIT_NEXT;
}
return IterationStatus.TERMINATED;
}
}
public FluentCollection<T> take(int size) {
return from(this.sources.limit(size));
}
public FluentCollection<T> takeWhile(final Predicate<T> fn) {
return from(new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return new TakeWhileIterator<T>(sources.iterator(), fn);
}
});
}
private static class TakeWhileIterator<TSource> extends AbstractPredicateEvalIterator<TSource> {
public TakeWhileIterator(Iterator<TSource> internalIterator, Predicate<TSource> predicator) {
super(internalIterator, predicator);
}
@Override
protected IterationStatus evaluate(Iterator<TSource> it, Predicate<TSource> fn) {
this.current = it.next();
return fn.apply(this.current) ? IterationStatus.WAIT_NEXT : IterationStatus.TERMINATED;
}
}
public FluentCollection<T> reverse() {
return from(this.toReverseList());
}
public T headOrElse(T defaultValue) {
Optional<T> result = this.head();
return result.isPresent() ? result.get() : defaultValue;
}
public Optional<T> head() {
return this.sources.first();
}
public <TKey> FluentCollection<GroupIterable<TKey, T>> groupBy(Function<? super T, TKey> keySelector) {
return from(this.toGroupDict(keySelector).entrySet())
.map(
new Function<Map.Entry<TKey, Collection<T>>, GroupIterable<TKey, T>>() {
@Override
public GroupIterable<TKey, T> apply(Map.Entry<TKey, Collection<T>> source) {
return new GroupIterable<TKey, T>(source.getKey(), source.getValue());
}
}
)
;
}
public T[] toArray(Class<T> type) {
return this.sources.toArray(type);
}
public List<T> toList() {
return this.sources.toList();
}
public List<T> toReverseList() {
return Lists.reverse(this.toList());
}
public T[] toReverseArray(Class<T> type) {
return from(this.toReverseList()).toArray(type);
}
public Set<T> toSet() {
return this.sources.toSet();
}
public <TKey> Map<TKey, T> toDict(Function<? super T, TKey> keySelector) {
return Maps.uniqueIndex(this.sources, keySelector);
}
public <TKey, TValue> Map<TKey, TValue> toDict(Function<? super T, TKey> keySelector, Function<? super T, TValue> valueSelector) {
return Maps.transformValues(
this.toDict(keySelector), valueSelector
);
}
public <TKey, TValue> Map<TKey, Collection<TValue>> toGroupDict(Function<? super T, TKey> keySelector, Function<? super T, TValue> valueSelector) {
return Multimaps
.transformValues(this.toMultimap(keySelector), valueSelector)
.asMap()
;
}
public <TKey> Map<TKey, Collection<T>> toGroupDict(Function<? super T, TKey> keySelector) {
return this.toMultimap(keySelector).asMap();
}
public <TKey> Multimap<TKey, T> toMultimap(Function<? super T, TKey> keySelector) {
return Multimaps.index(this.sources, keySelector);
}
public boolean any() {
return this.any(new Predicate<T>() {
@Override
public boolean apply(T source) {
return true;
}
});
}
public boolean any(Predicate<T> predicate) {
return this.sources.anyMatch(predicate);
}
public Optional<Integer> reduce(Function<? super T, Integer> fn) {
if (! this.any()) {
return Optional.absent();
}
else {
return Optional.of(this.reduce(0, fn));
}
}
public int reduce(int initial, Function<? super T, Integer> fn) {
for (T source: this.sources) {
initial += fn.apply(source);
}
return initial;
}
public BigDecimal reduce(BigDecimal initial, final Function<? super T, BigDecimal> fn) {
if (initial == null) initial = new BigDecimal(0);
return this.reduceInternal(initial, new Function3<BigDecimal, T, BigDecimal>() {
@Override
public BigDecimal apply(BigDecimal state, T source) {
return state.add(fn.apply(source));
}
});
}
public <TResult> Optional<TResult> reduce(TResult initial, Function3<TResult, ? super T, TResult> fn) {
return Optional.fromNullable(this.reduceInternal(initial, fn));
}
private <TResult> TResult reduceInternal(TResult initial, Function3<TResult, ? super T, TResult> fn) {
if (initial == null) return null;
TResult result = initial;
for (T source: this.sources) {
result = fn.apply(initial, source);
}
return result;
}
public static class UnfoldState<TSource> {
TSource current;
Optional<? extends TSource> next;
public UnfoldState(TSource current, Optional<? extends TSource> next) {
this.current = current;
this.next = next;
}
}
private static class UnfoldIterator<TSource> extends UnmodifiableIterator<TSource> {
private UnfoldState<TSource> state;
private Function<TSource, UnfoldState<TSource>> selector;
public UnfoldIterator(UnfoldState<TSource> initial, Function<TSource, UnfoldState<TSource>> selector) {
this.state = initial;
this.selector = selector;
}
@Override
public boolean hasNext() {
return this.state.next.isPresent();
}
@Override
public TSource next() {
this.state = this.selector.apply(this.state.next.get());
return this.state.current;
}
}
public static <TSource> FluentCollection<TSource> unfold(final TSource initial, final Function<TSource, UnfoldState<TSource>> selector) {
return from(new Iterable<TSource>() {
@Override
public Iterator<TSource> iterator() {
return new UnfoldIterator<TSource>(new UnfoldState<TSource>(initial, Optional.fromNullable(initial)), selector);
}
});
}
public FluentCollection<T> unique() {
return from(this.toSet());
}
public OrderedIterable<T> sort(Comparator<? super T> comparator) {
return new OrderedIterable<T>(this.sources, comparator, new ArrayList<Comparator<? super T>>());
}
private FluentCollection(FluentIterable<T> sources) {
this.sources = sources;
}
@Override
public Iterator<T> iterator() {
return this.sources.iterator();
}
}
package sample;
import java.util.Iterator;
public class GroupIterable<TKey, TValue> implements Iterable<TValue> {
private TKey key;
private Iterable<TValue> values;
GroupIterable(TKey key, Iterable<TValue> values) {
this.key = key;
this.values = values;
}
public TKey getKey() {
return this.key;
}
@Override
public Iterator<TValue> iterator() {
return this.values.iterator();
}
}
package sample;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import com.google.common.collect.Lists;
public class OrderedIterable<T> implements Iterable<T> {
private Iterable<T> sources;
private List<T> buf;
private List<Comparator<? super T>> comparators;
OrderedIterable(Iterable<T> sources, final Comparator<? super T> comparator, List<Comparator<? super T>> parentComparators) {
this.sources = sources;
this.comparators = new ArrayList<Comparator<? super T>>(parentComparators) {{ add(comparator); }};
}
@Override
public Iterator<T> iterator() {
if (this.buf == null) {
this.buf = Lists.newArrayList(this.sources);
Collections.sort(this.buf, new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
return doCompare(o1, o2);
}
});
}
return this.buf.iterator();
}
private int doCompare(T o1, T o2) {
int result = 0;
for (Comparator<? super T> c: this.comparators) {
result = c.compare(o1, o2);
if (result != 0) return result;
}
return result;
}
public OrderedIterable<T> thenBy(final Comparator<T> comparator) {
return new OrderedIterable<T>(this.sources, comparator, this.comparators);
}
public List<T> toList() {
return this.asFluent().toList();
}
public FluentCollection<T> asFluent() {
return FluentCollection.from(this);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment