package cs224n.util; import java.io.Serializable; import java.util.Map; import java.util.Set; import java.util.Collection; /** * A map from objects to doubles. Includes convenience methods for getting, * setting, and incrementing element counts. Objects not in the counter will * return a count of zero. The counter is backed by a HashMap (unless specified * otherwise with the MapFactory constructor). * * @author Dan Klein */ public class Counter <E> implements Serializable { static final long serialVersionUID = 1L; Map<E, Double> entries; /** * The elements in the counter. * * @return set of keys */ public Set<E> keySet() { return entries.keySet(); } /** * The number of entries in the counter (not the total count -- use totalCount() instead). */ public int size() { return entries.size(); } /** * True if there are no entries in the counter (false does not mean totalCount > 0) */ public boolean isEmpty() { return size() == 0; } /** * Returns whether the counter contains the given key. Note that this is the * way to distinguish keys which are in the counter with count zero, and those * which are not in the counter (and will therefore return count zero from * getCount(). * * @param key * @return whether the counter contains the key */ public boolean containsKey(E key) { return entries.containsKey(key); } /** * Get the count of the element, or zero if the element is not in the * counter. * * @param key */ public double getCount(E key) { Double value = entries.get(key); if (value == null) return 0; return value; } /** * Set the count for the given key, clobbering any previous count. * (Alec's update: If the count is 0, it will remove the key from the map.) * * @param key * @param count */ public void setCount(E key, double count) { if(count == 0.0) { entries.remove(key); } else { entries.put(key, count); } } /** * Increment a key's count by the given amount. * * @param key * @param increment */ public void incrementCount(E key, double increment) { setCount(key, getCount(key) + increment); } /** * Increment each element in a given collection by a given amount. */ public void incrementAll(Collection<? extends E> collection, double count) { for (E key : collection) { incrementCount(key, count); } } public <T extends E> void incrementAll(Counter<T> counter) { for (T key : counter.keySet()) { double count = counter.getCount(key); incrementCount(key, count); } } /** * Finds the total of all counts in the counter. This implementation iterates * through the entire counter every time this method is called. * * @return the counter's total */ public double totalCount() { double total = 0.0; for (Map.Entry<E, Double> entry : entries.entrySet()) { total += entry.getValue(); } return total; } /** * Finds the key with maximum count. This is a linear operation, and ties are broken arbitrarily. * * @return a key with minumum count */ public E argMax() { double maxCount = Double.NEGATIVE_INFINITY; E maxKey = null; for (Map.Entry<E, Double> entry : entries.entrySet()) { if (entry.getValue() > maxCount || maxKey == null) { maxKey = entry.getKey(); maxCount = entry.getValue(); } } return maxKey; } /** * Returns a string representation with the keys ordered by decreasing * counts. * * @return string representation */ public String toString() { return toString(keySet().size()); } /** * Returns a string representation which includes no more than the * maxKeysToPrint elements with largest counts. * * @param maxKeysToPrint * @return partial string representation */ public String toString(int maxKeysToPrint) { return asPriorityQueue().toString(maxKeysToPrint); } /** * Builds a priority queue whose elements are the counter's elements, and * whose priorities are those elements' counts in the counter. */ public PriorityQueue<E> asPriorityQueue() { PriorityQueue<E> pq = new PriorityQueue<E>(entries.size()); for (Map.Entry<E, Double> entry : entries.entrySet()) { pq.add(entry.getKey(), entry.getValue()); } return pq; } public Counter() { this(new MapFactory.HashMapFactory<E, Double>()); } public Counter(MapFactory<E, Double> mf) { entries = mf.buildMap(); } public static void main(String[] args) { Counter<String> counter = new Counter<String>(); System.out.println(counter); counter.incrementCount("planets", 7); System.out.println(counter); counter.incrementCount("planets", 1); System.out.println(counter); counter.setCount("suns", 1); System.out.println(counter); counter.setCount("aliens", 0); System.out.println(counter); System.out.println(counter.toString(2)); System.out.println("Total: " + counter.totalCount()); } }