package sizzle.aggregators;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
/**
* A sorted counting set. Like a SortedSet, but also keeps track of how many
* times a given member has been added.
*
* @author anthonyu
*
* @param <T>
* The type of value that will be inserted into the set
*/
public class SortedCountingSet<T> implements Iterable<T> {
private final TreeMap<T, Long> map;
/**
* Construct a SortedCountingSet.
*/
public SortedCountingSet() {
this.map = new TreeMap<T, Long>();
}
/**
* Add a value to the set.
*
* @param t
* The value to be added
*/
public void add(final T t) {
// add it with cardinality 1
this.add(t, 1);
}
/**
* Add a value and its cardinality to the set.
*
* @param t
* The value to be added
* @param n
* The cardinality of the value
*/
public void add(final T t, final long n) {
// if the map already has this key, add n to the current cardiality and
// reinsert
if (this.map.containsKey(t))
this.map.put(t, Long.valueOf(this.map.get(t).longValue() + n));
else
this.map.put(t, Long.valueOf(n));
}
/** {@inheritDoc} */
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
private Entry<T, Long> lastEntry;
private Entry<T, Long> thisEntry;
private long cursor;
{
this.thisEntry = SortedCountingSet.this.map.firstEntry();
this.lastEntry = SortedCountingSet.this.map.lastEntry();
this.cursor = 0;
}
@Override
public boolean hasNext() {
if (this.lastEntry == null)
return false;
if (!this.thisEntry.getKey().equals(this.lastEntry.getKey()))
return true;
return this.cursor != this.lastEntry.getValue().longValue();
}
@Override
public T next() {
if (this.cursor == this.thisEntry.getValue().longValue()) {
this.thisEntry = SortedCountingSet.this.map.higherEntry(this.thisEntry.getKey());
this.cursor = 0;
}
this.cursor++;
return this.thisEntry.getKey();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Copy this set into a {@link List}.
*
* @return A {@link List} containing the values in this set
*/
public List<T> toList() {
final List<T> l = new ArrayList<T>();
for (final T t : this)
l.add(t);
return l;
}
/**
* Get the entries in this set.
*
* @return A {@link Set} of Map.Entry containing the entries in this set
*/
public Set<java.util.Map.Entry<T, Long>> getEntries() {
return this.map.entrySet();
}
}