Mega Code Archive

 
Categories / Java / Collections Data Structure
 

A simple Map implementation

/*  * Copyright (c) Ian F. Darwin, http://www.darwinsys.com/, 1996-2002.  * All rights reserved. Software written by Ian F. Darwin and others.  * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $  *  * Redistribution and use in source and binary forms, with or without  * modification, are permitted provided that the following conditions  * are met:  * 1. Redistributions of source code must retain the above copyright  *    notice, this list of conditions and the following disclaimer.  * 2. Redistributions in binary form must reproduce the above copyright  *    notice, this list of conditions and the following disclaimer in the  *    documentation and/or other materials provided with the distribution.  *  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  * POSSIBILITY OF SUCH DAMAGE.  *   * Java, the Duke mascot, and all variants of Sun's Java "steaming coffee  * cup" logo are trademarks of Sun Microsystems. Sun's, and James Gosling's,  * pioneering role in inventing and promulgating (and standardizing) the Java   * language and environment is gratefully acknowledged.  *   * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for  * inventing predecessor languages C and C++ is also gratefully acknowledged.  */ import java.util.*; /** A simple Map implementation, implemented in terms of a  * pair of ArrayLists just to show what a Map has to do (it would   * have been easier, but less informative, to subclass AbstractMap).  * This Map implementation, like TreeSet, guarantees that the   * Map's contents will be kept in ascending element order,   * sorted according to the natural order of the elements;  * see Comparable. This does not (yet) allow you to specify your own  * Comparator.  * <p>  * It is a requirement that all objects inserted be able to   * call compareTo on all other objects, i.e., they must all  * be of the same or related classes.  * <p>  * Be warned that the entrySet() method is <b>not implemented</b> yet.  */ public class MyMap implements Map {   private ArrayList keys;   private ArrayList values;   public MyMap() {     keys = new ArrayList();     values = new ArrayList();   }   /** Return the number of mappings in this Map. */   public int size() {     return keys.size();   }   /** Return true if this map is empty. */   public boolean isEmpty() {     return size() == 0;   }   /** Return true if o is contained as a Key in this Map. */   public boolean containsKey(Object o) {     return keys.contains(o);   }   /** Return true if o is contained as a Value in this Map. */   public boolean containsValue(Object o) {     return keys.contains(o);   }   /** Get the object value corresponding to key k. */   public Object get(Object k) {     int i = keys.indexOf(k);     if (i == -1)       return null;     return values.get(i);   }   /** Put the given pair (k, v) into this map, by maintaining "keys"    * in sorted order.    */   public Object put(Object k, Object v) {     for (int i=0; i < keys.size(); i++) {       Object old = keys.get(i);       /* Does the key already exist? */       if (((Comparable)k).compareTo(keys.get(i)) == 0) {         keys.set(i, v);         return old;       }       /* Did we just go past where to put it?        * i.e., keep keys in sorted order.        */       if (((Comparable)k).compareTo(keys.get(i)) == +1) {         int where = i > 0 ? i -1 : 0;         keys.add(where, k);         values.add(where, v);         return null;       }     }     // Else it goes at the end.     keys.add(k);     values.add(v);     return null;   }   /** Put all the pairs from oldMap into this map */   public void putAll(java.util.Map oldMap) {     Iterator keysIter = oldMap.keySet().iterator();     while (keysIter.hasNext()) {       Object k = keysIter.next();       Object v = oldMap.get(k);       put(k, v);     }   }   public Object remove(Object k) {     int i = keys.indexOf(k);     if (i == -1)       return null;     Object old = values.get(i);     keys.remove(i);     values.remove(i);     return old;   }   public void clear() {     keys.clear();     values.clear();   }   public java.util.Set keySet() {     return new TreeSet(keys);   }   public java.util.Collection values() {     return values;   }   /** The Map.Entry objects contained in the Set returned by entrySet().    */   private class MyMapEntry implements Map.Entry, Comparable {     private Object key, value;     MyMapEntry(Object k, Object v) {       key = k;       value = v;     }     public Object getKey() { return key; }     public Object getValue() { return value; }     public Object setValue(Object nv) {       throw new UnsupportedOperationException("setValue");     }     public int compareTo(Object o2) {       if (!(o2 instanceof MyMapEntry))         throw new IllegalArgumentException(           "Huh? Not a MapEntry?");       Object otherKey = ((MyMapEntry)o2).getKey();       return ((Comparable)key).compareTo((Comparable)otherKey);     }     }   /** The set of Map.Entry objects returned from entrySet(). */   private class MyMapSet extends AbstractSet {     List list;     MyMapSet(ArrayList al) {       list = al;     }     public Iterator iterator() {       return list.iterator();     }     public int size() {       return list.size();     }   }   /** Returns a set view of the mappings contained in this Map.    * Each element in the returned set is a Map.Entry.    * NOT guaranteed fully to implement the contract of entrySet    * declared in java.util.Map.    */     public java.util.Set entrySet() {     if (keys.size() != values.size())       throw new IllegalStateException(         "InternalError: keys and values out of sync");     ArrayList al = new ArrayList();     for (int i=0; i<keys.size(); i++) {       al.add(new MyMapEntry(keys.get(i), values.get(i)));     }     return new MyMapSet(al);    }   public static void main(String[] argv) {     // Construct and load the hash. This simulates loading a     // database or reading from a file, or wherever the data is.     Map map = new MyMap();     // The hash maps from company name to address.     // In real life this might map to an Address object...     map.put("Adobe", "Mountain View, CA");     map.put("Learning Tree", "Los Angeles, CA");     map.put("IBM", "White Plains, NY");     map.put("Netscape", "Mountain View, CA");     map.put("Microsoft", "Redmond, WA");     map.put("Sun", "Mountain View, CA");     map.put("O'Reilly", "Sebastopol, CA");     // Two versions of the "retrieval" phase.     // Version 1: get one pair's value given its key     // (presumably the key would really come from user input):     String queryString = "O'Reilly";     System.out.println("You asked about " + queryString + ".");     String resultString = (String)map.get(queryString);     System.out.println("They are located in: " + resultString);     System.out.println();     // Version 2: get ALL the keys and pairs      // (maybe to print a report, or to save to disk)     Iterator k = map.keySet().iterator();     while (k.hasNext()) {       String key = (String) k.next();       System.out.println("Key " + key + "; Value " +         (String) map.get(key));     }     // Step 3 - try out the entrySet() method.     Set es = map.entrySet();     System.out.println("entrySet() returns " + es.size() + " Map.Entry's");   } }