package de.blau.android.util.collections; import java.io.Serializable; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; /** * This data structure is a combination of a Map and Set. * Each key can be assigned not one, but multiple values. * Sorted map/set implementations are used to guarantee (case-sensitive) alphabetical sorting of entries. * @author Jan * * @param <K> Key type * @param <V> Type of the values to be associated with the keys */ public class MultiHashMap<K, V> implements Serializable { /** * */ private static final long serialVersionUID = 1L; private Map<K, Set<V>> map; private boolean sorted; /** Creates a regular, unsorted MultiHashMap */ public MultiHashMap() { this(false); } /** * Creates a MultiHashMap. * @param sorted if true, Tree maps/sets will be used, if false, regular HashMap/HashSets will be used. */ public MultiHashMap(boolean sorted) { this.sorted = sorted; if (sorted) { map = new TreeMap<K, Set<V>>(); } else { map = new HashMap<K, Set<V>>(); } } /** * Check for key in map * @param key * @return true if key exists in map */ public boolean containsKey(K key) { return map.containsKey(key); } /** * Adds item to the set of values associated with the key (null items are not added) * @returns true if the element was added, false if it was already in the set or null */ public boolean add(K key, V item) { Set<V> values = map.get(key); if (values == null) { values = (sorted ? new TreeSet<V>() : new HashSet<V>()); map.put(key, values); } return item != null && values.add(item); } /** * Adds all items to the set of values associated with the key * @param key the key * @param items an array containing the items */ public void add(K key, V[] items) { Set<V> values = map.get(key); if (values == null) { values = (sorted ? new TreeSet<V>() : new HashSet<V>()); map.put(key, values); } values.addAll(Arrays.asList(items)); } /** * Adds all items to the set of values associated with the key * @param key the key * @param items a set containing the items */ private void add(K key, Set<V> items) { Set<V> values = map.get(key); if (values == null) { values = (sorted ? new TreeSet<V>() : new HashSet<V>()); map.put(key, values); } values.addAll(items); } /** * Removes the item from the set associated with the given key * @param key * @param item the item to remove * @return true if the item was in the set */ public boolean removeItem(K key, V item) { Set<V> values = map.get(key); if (values != null) return values.remove(item); return false; } /** * Completely removes all values associated with a key * @param key */ public void removeKey(K key) { map.remove(key); } /** * Gets the list of items associated with a key. * @param key * @return a unmodifiable list of the items associated with the key, may be empty but never null */ public Set<V> get(K key) { Set<V> values = map.get(key); if (values == null) return Collections.emptySet(); return Collections.unmodifiableSet(values); } /** * Guess what. */ public void clear() { map.clear(); } public Set<K> getKeys() { return map.keySet(); } /** * return all values * @return */ public Set<V> getValues() { Set<V> retval = new LinkedHashSet<V>(); for (K key: getKeys()) { retval.addAll(get(key)); } return retval; } /** * add all key/values from source to this Map * @param source */ public void addAll(MultiHashMap<K, V> source) { for (K key:source.getKeys()) { add(key,source.get(key)); } } }