1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package net.sf.statcvs.util;
24
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.Comparator;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.TreeMap;
33
34 /**
35 * Utility class for storing a map from <code>Object</code>s to
36 * <code>int</code>s.
37 * This class makes it easy to sort by key or value, and provides
38 * useful features like {@link #sum()}, {@link #max()}, and
39 * percent calculation.
40 * <p>
41 * The keys must be comparable, for example <code>String</code>s.
42 * <p>
43 * Behaviour for <code>null</code> keys is unspecified.
44 *
45 * @author Richard Cyganiak
46 * @version $Id: IntegerMap.java,v 1.16 2008/04/02 11:52:02 benoitx Exp $
47 */
48 public class IntegerMap {
49
50 private final Map map = new TreeMap();
51 private final Comparator comparator = new SortByValueComparator(map);
52 private int sum = 0;
53 private int max = 0;
54
55 /**
56 * Puts a value into the map, overwriting any previous value
57 * for the same key.
58 *
59 * @param key an <code>Object</code> which is used as key.
60 * @param value the <code>int</code> value to be stored at this key.
61 */
62 public void put(final Object key, final int value) {
63 max = Math.max(max, value);
64 sum -= get(key);
65 sum += value;
66 map.put(key, new Integer(value));
67 }
68
69 /**
70 * Gets a value from the map. Returns the value which was
71 * stored in the map at the same key before. If no value was
72 * stored for this key, 0 will be returned.
73 *
74 * @param key an <code>Object</code> which is used as key.
75 * @return the value for this key
76 */
77 public int get(final Object key) {
78 final Integer result = (Integer) map.get(key);
79 if (result == null) {
80 return 0;
81 }
82 return result.intValue();
83 }
84
85 /**
86 * Same as {@link #get(Object)}, but returns an <code>Integer</code>,
87 * not an <code>int</code>.
88 *
89 * @param key the key to get the value for
90 * @return the value wrapped in an <code>Integer</code> object
91 */
92 public Integer getInteger(final Object key) {
93 return (Integer) map.get(key);
94 }
95
96 /**
97 * Gets the value stored at a key as a percentage of all values
98 * in the map.
99 *
100 * @param key the key to get the value for
101 * @return the value as a percentage of the sum of all values
102 */
103 public double getPercent(final Object key) {
104 return (double) get(key) * 100 / sum;
105 }
106
107 /**
108 * Gets the value stored at a key as a percentage of the maximum
109 * value in the map. For the maximum value, this will return
110 * 100.0. For a value half as large as the maximum value, this
111 * will return 50.0.
112 *
113 * @param key the key to get the value for
114 * @return the value as a percentage of largest value in the map
115 */
116 public double getPercentOfMaximum(final Object key) {
117 return get(key) * 100 / max;
118 }
119
120 /**
121 * Adds an <code>int</code> to the value stored at a key.
122 * If no value was stored before at this key, the <code>int</code>
123 * will be stored there.
124 *
125 * @param key the key to whose value <code>addValue</code> should be added
126 * @param addValue the <code>int</code> to be added
127 */
128 public void addInt(final Object key, final int addValue) {
129 put(key, addValue + get(key));
130 }
131
132 /**
133 * Same as <code>addInt(key, 1)</code>
134 *
135 * @param key the key whose value should be increased
136 */
137 public void inc(final Object key) {
138 addInt(key, 1);
139 }
140
141 /**
142 * Same as <code>addInt(key, -1)</code>
143 *
144 * @param key the key whose value should be decreased
145 */
146 public void dec(final Object key) {
147 addInt(key, -1);
148 }
149
150 /**
151 * Deletes a value from the map. This is different from
152 * <code>put(key, 0)</code>. Removing will reduce
153 * the size of the map, putting 0 will not.
154 *
155 * @param key the key that should be removed
156 */
157 public void remove(final Object key) {
158 sum -= get(key);
159 map.remove(key);
160 }
161
162 /**
163 * Returns <code>true</code> if the map contains a value
164 * for this key.
165 *
166 * @param key the key to check for
167 * @return <code>true</code> if the key is in the map
168 */
169 public boolean contains(final Object key) {
170 return map.containsKey(key);
171 }
172
173 /**
174 * Returns the number of key-value pairs stored in the map.
175 *
176 * @return the number of key-value pairs stored in the map
177 */
178 public int size() {
179 return map.size();
180 }
181
182 /**
183 * Returns a set view of the keys. The set will be in
184 * ascending key order.
185 *
186 * @return a <code>Set</code> view of all keys
187 */
188 public Set keySet() {
189 return map.keySet();
190 }
191
192 /**
193 * Returns an iterator on the keys, sorted by key ascending.
194 *
195 * @return an iterator on the keys
196 */
197 public Iterator iteratorSortedByKey() {
198 return map.keySet().iterator();
199 }
200
201 /**
202 * Returns an iterator on the keys, sorted by values ascending.
203 *
204 * @return an iterator on the keys
205 */
206 public Iterator iteratorSortedByValue() {
207 final List keys = new ArrayList(map.keySet());
208 Collections.sort(keys, comparator);
209 return keys.iterator();
210 }
211
212 /**
213 * Returns an iterator on the keys, sorted by values descending.
214 *
215 * @return an iterator on the keys
216 */
217 public Iterator iteratorSortedByValueReverse() {
218 final List keys = new ArrayList(map.keySet());
219 Collections.sort(keys, comparator);
220 Collections.reverse(keys);
221 return keys.iterator();
222 }
223
224 /**
225 * Returns the sum of all values in the map.
226 *
227 * @return the sum of all values in the map
228 */
229 public int sum() {
230 return sum;
231 }
232
233 /**
234 * Returns the average of all values in the map.
235 *
236 * @return the average of all values in the map
237 */
238 public double average() {
239 return (double) sum() / size();
240 }
241
242 /**
243 * Returns the maximum value in the map.
244 *
245 * @return the maximum value in the map.
246 */
247 public int max() {
248 return max;
249 }
250
251 /**
252 * Private utility class for comparing of map entries by value.
253 */
254 private static class SortByValueComparator implements Comparator {
255 private final Map mapToBeSorted;
256
257 public SortByValueComparator(final Map map) {
258 this.mapToBeSorted = map;
259 }
260
261 public int compare(final Object o1, final Object o2) {
262 final int i1 = ((Integer) this.mapToBeSorted.get(o1)).intValue();
263 final int i2 = ((Integer) this.mapToBeSorted.get(o2)).intValue();
264 if (i1 < i2) {
265 return -1;
266 } else if (i1 > i2) {
267 return 1;
268 }
269 return 0;
270 }
271 }
272 }