Last active
August 29, 2015 14:18
-
-
Save danieldietrich/3a80c0e788ed1524ae64 to your computer and use it in GitHub Desktop.
A coproduct on Iterables providing collection concatenation in O(1)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.*; | |
/** | |
* <p> | |
* Colist is a view on Iterables, more specific a disjoint union of Iterables. In fact, Colist is an | |
* algebraic data type, namely a coproduct (see <a | |
* href="http://en.wikipedia.org/wiki/Coproduct">Wikipedia</a>). Iterables like List, Set and also | |
* Colist can be concatenated in constant time. | |
* </p> | |
* For example, instead of | |
* | |
* <pre> | |
* <code>final List<T> list1 = getList1(); | |
* final List<T> list2 = getList2(); | |
* final List<T> newList = new ArrayList<>(list1); | |
* newList.addAll(list2); | |
* for(List<T> list : lists) { | |
* newList.addAll(list); | |
* }</code> | |
* </pre> | |
* | |
* we would write | |
* | |
* <pre> | |
* <code>final List<T> newList = new Colist<>(getList1(), getList1()) | |
* .addAll(lists) | |
* .toList();</code> | |
* </pre> | |
* | |
* <p> | |
* Because Colist is an Iterable, we may call {@code for(T t : colist)}, given a | |
* {@code Colist<T> colist}. | |
* </p> | |
*/ | |
public final class Colist<T> implements Iterable<T> { | |
private static final Iterator<Object> EMPTY_ITERATOR = new Iterator<Object>() { | |
@Override | |
public boolean hasNext() { | |
return false; | |
} | |
@Override | |
public Object next() { | |
throw new NoSuchElementException(); | |
} | |
@Override | |
public void remove() { | |
throw new UnsupportedOperationException(); | |
} | |
}; | |
private final List<Iterable<? extends T>> iterables; | |
/** | |
* Constructs a Colist. Adds all elements of all given iterables to this Colist in constant time | |
* O(iterables.length) = O(1). | |
* | |
* @param iterables an array of Iterable, none of them may be null | |
*/ | |
@SuppressWarnings("unchecked") | |
public Colist(Iterable<? extends T>... iterables) { | |
this.iterables = new LinkedList<>(); | |
for (Iterable<? extends T> iterable : iterables) { | |
this.iterables.add(iterable); | |
} | |
} | |
/** | |
* Adds all elements of an iterable to this Colist in constant time O(1). | |
* | |
* @param iterable An iterable | |
* @return this Colist instance | |
*/ | |
public Colist<T> add(Iterable<? extends T> iterable) { | |
this.iterables.add(iterable); | |
return this; | |
} | |
/** | |
* Adds all elements of all given iterables to this Colist in constant time O(iterables.length) | |
* = O(1). | |
* | |
* @param iterable An iterable | |
* @return this Colist instance | |
*/ | |
@SuppressWarnings("unchecked") | |
public Colist<T> addAll(Iterable<? extends T>... iterables) { | |
for (Iterable<? extends T> iterable : iterables) { | |
this.iterables.add(iterable); | |
} | |
return this; | |
} | |
/** | |
* Returns a new List instance containing all elements of this Colist. | |
* | |
* @return A new List instance. | |
*/ | |
public List<T> toList() { | |
return toCollection(new ArrayList<T>()); | |
} | |
/** | |
* Returns a new Set instance containing all elements of this Colist. | |
* | |
* @return A new Set instance. | |
*/ | |
public Set<T> toSet() { | |
return toCollection(new HashSet<T>()); | |
} | |
/** | |
* Returns a new SortedSet instance containing all elements of this Colist in their natural | |
* order. | |
* | |
* @return A new SortedSet instance. | |
*/ | |
public SortedSet<T> toSortedSet() { | |
return toCollection(new TreeSet<T>()); | |
} | |
/** | |
* Returns a new SortedSet instance containing all elements of this Colist in the order defined | |
* by the given comparator. | |
* | |
* @return A new SortedSet instance. | |
*/ | |
public SortedSet<T> toSortedSet(Comparator<? super T> comparator) { | |
return toCollection(new TreeSet<>(comparator)); | |
} | |
private <C extends Collection<T>> C toCollection(C collection) { | |
for(T t : this) { | |
collection.add(t); | |
} | |
return collection; | |
} | |
@Override | |
public Iterator<T> iterator() { | |
return flatten(iterables.iterator()); | |
} | |
private static <T> Iterator<T> flatten(final Iterator<? extends Iterable<? extends T>> inputs) { | |
return new Iterator<T>() { | |
@SuppressWarnings("unchecked") | |
Iterator<? extends T> current = (Iterator<? extends T>) EMPTY_ITERATOR; | |
@Override | |
public boolean hasNext() { | |
boolean currentHasNext; | |
while(!(currentHasNext = current.hasNext()) && inputs.hasNext()) { | |
current = inputs.next().iterator(); | |
} | |
return currentHasNext; | |
} | |
@Override | |
public T next() { | |
if(!hasNext()) { | |
throw new NoSuchElementException(); | |
} | |
return current.next(); | |
} | |
@Override | |
public void remove() { | |
throw new UnsupportedOperationException(); | |
} | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thx for the hint @szarnekow !