CollectingIterable.java
- package no.motif.iter;
- import static java.util.Collections.sort;
- import static java.util.Collections.unmodifiableList;
- import static no.motif.Base.toString;
- import static no.motif.Iterate.by;
- import static no.motif.Singular.optional;
- import static no.motif.Strings.concat;
- import java.io.Serializable;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Comparator;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
- import no.motif.Singular;
- import no.motif.Strings;
- import no.motif.f.Do;
- import no.motif.f.Fn;
- import no.motif.f.Fn2;
- import no.motif.f.Predicate;
- import no.motif.single.Optional;
- import no.motif.types.Elements;
- /**
- * This iterable offers operations which requires collecting (i.e.
- * iterating) the containing elements of the iterable. In
- * particular, this class holds the methods which "bridges" back
- * to the non-lazy Java Collection Framework classes.
- *
- * @param <T> The type of elements in this iterable.
- */
- abstract class CollectingIterable<T> implements Elements<T>, Serializable {
- @Override
- public final <O> O reduce(O unit, Fn2<? super O, ? super T, ? extends O> reducer) {
- O reduced = unit;
- for (T element : this) reduced = reducer.$(reduced, element);
- return reduced;
- }
- @Override
- public final List<T> collect() {
- return unmodifiableList(collectIn(new ArrayList<T>()));
- }
- @Override
- public final <C extends Collection<T>> C collectIn(C collection) {
- for (T t : this) {
- collection.add(t);
- }
- return collection;
- }
- @Override
- public final <P extends Comparable<P>> List<T> sortedBy(Fn<? super T, P> property) {
- return sorted(by(property));
- }
- @Override
- public final List<T> sorted(Comparator<? super T> comparator) {
- List<T> elements = collectIn(new ArrayList<T>());
- sort(elements, comparator);
- return unmodifiableList(elements);
- }
- @Override
- public void each(Do<? super T> sideEffect) {
- for (T element : this) sideEffect.with(element);
- }
- @Override
- public <P> Map<P, List<T>> groupBy(Fn<? super T, P> property) {
- Map<P, List<T>> map = new LinkedHashMap<>();
- for (T elem : this) {
- P key = property.$(elem);
- List<T> list;
- if (!map.containsKey(key)) {
- list = new ArrayList<>();
- map.put(key, list);
- } else {
- list = map.get(key);
- }
- list.add(elem);
- }
- return map;
- }
- @Override
- public <P> Map<P, T> mapBy(Fn<? super T, P> uniqueProperty) {
- Map<P, T> map = new LinkedHashMap<>();
- for (T elem : this) {
- P key = uniqueProperty.$(elem);
- if (!map.containsKey(key)) map.put(key, elem);
- else throw new IllegalStateException(
- "Cannot create the map since both '" + map.get(key) + "' and '" + elem + "' yields " +
- "the same key: '" + key + "'. This is either due to an inconsistency in " +
- "your data, or you should use .groupBy(Fn) instead to allow multiple elements " +
- "being mapped by the same key.");
- }
- return map;
- }
- @Override
- public boolean isEmpty() {
- return !iterator().hasNext();
- }
- @Override
- public boolean exists(Predicate<? super T> predicate) {
- for (T t : this) if (predicate.$(t)) return true;
- return false;
- }
- @Override
- public Optional<T> head() {
- return !isEmpty() ? optional(iterator().next()) : Singular.<T>none();
- }
- @Override
- public Optional<T> last() {
- T last = null;
- for (T elem : this) last = elem;
- return optional(last);
- }
- @Override
- public String join() {
- return reduce("", concat);
- }
- @Override
- public String join(String separator) {
- if (isEmpty()) return "";
- return head().map(toString).append(tail().map(Strings.prepend(separator))).reduce("", concat);
- }
- /**
- * Textual description of the contents of the iterable. Have in mind that for lazy
- * implementations, using {@link #toString()} will iterate over the elements to
- * actually be able to create the description.
- */
- @Override
- public String toString() {
- return collect().toString();
- }
- }