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