SE251:jhor053sMultiMap
Here is my multi map as per showcased in the 251 Group Session 5
Any q's or comments let me know on my talk page or here Jhor053 22:13, 11 May 2008 (NZST)
If you use this for something Include Hong Yul Yang and I please and feel free to modify it and post it up on another wiki page and post your link also on here!
//package movies.core; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; /** * A multi-map stores mapping from a key (type K) to a set of elements (type V) * A many to many * * @origAuthor Hong Yul Yang (based of his Skeleton code from 251 wiki) * @author jhor053 * */ public class MultiMap<K,V> { //private Map<K,Set<V>> backingMap; private Map<K, Set<V>> backingMap; private Map<V, Set<K>> reverseMap; /** * Constructs an empty MultiMap */ public MultiMap() { backingMap = new TreeMap<K, Set<V>> (); reverseMap = new TreeMap<V, Set<K>> (); } /** * Returns the set of all keys that have at least one associated value * in this multimap. * @return a set containing all keys */ public Set<K> keySet() { return backingMap.keySet(); } /** * Returns the set of all values that have at least one associated key * in this multimap * @return a set containing all values */ public Set<V> valueSet() { //Uses the reverse map to get a quick set of the values return reverseMap.keySet(); } /** * Adds the specified value to the set associated with the specified key. * Note, if the key doesn't have an associated set, you would have to create * and associate it first before adding the value to it. * @param key * @param value * @return true if the set associated with the key didn't contain value previously; * false if it did (i.e. nothing was added) */ public boolean add(K key, V value) { //Safety to get rid of false alignments if(key == null || value == null) return false; //Checks too see if it is already assigned if(containsValueAssignedToKey(key, value)) return false; //Initialising variable names for the sets Set <V> vSet; Set <K> kSet; //Seeing if the reference is non existant //I.e. either the key is present if (backingMap.get(key) != null){ vSet = backingMap.get(key); }else{ //I.e. key has nothing assigned or non existant key vSet = new TreeSet<V> (); } //Add the value to the set to be assigned vSet.add(value); //Seeing if the reference is non existant //I.e. either the value is present if(reverseMap.get(value) != null){ kSet = reverseMap.get(value); }else{ //I.e. value has nothing assigned or non existant value kSet = new TreeSet<K> (); } //Add the key to the set to be assigned kSet.add(key); //Saving references backingMap.put(key, vSet); reverseMap.put(value, kSet); return true; } /** * Removes the specified value from the set associated with the specified key. * If the set becomes empty as a result, then also removes its association to the key * altogether. Thus, the set returned from subsequent calls to keySet() would not * contain this key anymore. * Note, if the set associated with the key doesn't contain the value, nothing * is done. * @param key * @param value * @return true if the value successfully was removed; false if the set associated * with the key didn't contain value */ public boolean remove(K key, V value) { if(containsValueAssignedToKey(key, value)){ //initialise Sets Set <V> vSet = backingMap.get(key); Set <K> kSet; //boolean removeKey = false; //Remove the value from the normal map if(vSet.remove(value)){ //IE no more occurrences of the key if(vSet.isEmpty()){ //removing key as nothing assigned to it backingMap.remove(key); //removeKey = true; }else{//Still have references for the key backingMap.put(key, vSet); } //Get all references kSet = reverseMap.get(value); //Ie occurrences of the value if(kSet != null){ kSet.remove(key); //update refferences on the reverse map if(kSet.isEmpty()){ reverseMap.remove(value); }else{ reverseMap.put(value, kSet); } } return true; } } return false; } /** * Removes the specified key from the set associated with the specified value. * If the set becomes empty as a result, then also removes its association to the key * altogether. Thus, the set returned from subsequent calls to keySet() would not * contain this key anymore. * Note, if the set associated with the key doesn't contain the value, nothing * is done. * @param value * @return true if the value successfully was removed; false if the set associated * with the key didn't contain value */ public boolean removeKey(K key) { if(backingMap.containsKey(key)){ Set<V> tempSet = backingMap.remove(key); for (Iterator<V> iterator = tempSet.iterator(); iterator.hasNext();) { V v = iterator.next(); Set<K> tempSet2 = reverseMap.get(v); if(tempSet2 != null){ tempSet2.remove(key); if(tempSet2.isEmpty()){ reverseMap.remove(v); }else{ reverseMap.put(v, tempSet2); } } } return true; } return false; } /** * Removes the specified value from the set associated with the specified key. * If the set becomes empty as a result, then also removes its association to the key * altogether. Thus, the set returned from subsequent calls to keySet() would not * contain this key anymore. * Note, if the set associated with the key doesn't contain the value, nothing * is done. * @param value * @return true if the value successfully was removed; false if the set associated * with the key didn't contain value */ public boolean removeValue(V value) { if(reverseMap.containsKey(value)){ Set<K> tempSet = reverseMap.remove(value); for (Iterator<K> iterator = tempSet.iterator(); iterator.hasNext();) { K k = iterator.next(); Set<V> tempSet2 = backingMap.get(k); if(tempSet2 != null){ tempSet2.remove(value); if(tempSet2.isEmpty()){ backingMap.remove(k); }else{ backingMap.put(k, tempSet2); } } } return true; } return false; } /** * Returns the set associated with the given key. Returns an empty * set if the key has no associations. * * @param key * @return the set associated with the given key */ public Set<V> get(K key) { Set <V> returnSet = new TreeSet<V>(); if(backingMap.get(key) == null) return returnSet; returnSet = backingMap.get(key); return returnSet; } /** * Returns the set associated with the given value. Returns an empty * set if the value has no associations. * * @param key * @return the set associated with the given key */ public Set<K> getKeySetFromValue(V value) { Set <K> returnSet = new TreeSet<K>(); if(reverseMap.get(value) == null) return returnSet; returnSet = reverseMap.get(value); return returnSet; } /** * Returns a string representation of this multimap in the form of e.g. * [key1=[val1, val2], key2=[val1, val3, val4], key3=[val3]]. * * @return the string representation of this multimap */ public String toString() { return backingMap.toString(); } /** * Checks to see if a specified value is assigned to a key * * @param key * @param value * @return true if the value is assigned to that key */ public boolean containsValueAssignedToKey (K key, V value){ if( backingMap.containsKey(key) ){ //Get the Set<V> as per specified by the key Set<V> testSet = backingMap.get(key); //See if testSet Contains the specified value if(testSet.contains(value)) return true; } return false; } /** * Checks to see if a specified key is assigned to a Value * * @param value * @param key * @return true if the key is assigned to that value */ public boolean containsKeyAssignedToValue (V value, K key){ if( reverseMap.containsKey(value) ){ //Get the Set<V> as per specified by the key Set<K> testSet = reverseMap.get(value); //See if testSet Contains the specified value if(testSet.contains(key)) return true; } return false; } /** * Implements containKey() from Map * * @param key * @return True if it contains specified key */ public boolean containsKey(K key){ return backingMap.containsKey(key); } /** * Implements containValue() from Map * * @param key * @return True if it contains specified Value */ public boolean containsValue(V value){ return reverseMap.containsKey(value); } }