Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Hashtable question

Reply
Thread Tools

Hashtable question

 
 
Nathan Bragg
Guest
Posts: n/a
 
      05-11-2004
Is there a way using a Hashtable, or some other object to give the
object a value and return all the keys that have that value? So if I
have something like:

hashtable.put("A","1");
hashtable.put("B","1");
hashtable.put("C","1");
hashtable.put("D","2");

I could pass in "1" and it would return a Vector or Array with
"A","B","C" in it? Thanks for any help in advance.

- Nathan Bragg
 
Reply With Quote
 
 
 
 
Michael Borgwardt
Guest
Posts: n/a
 
      05-11-2004
Nathan Bragg wrote:

> Is there a way using a Hashtable, or some other object to give the
> object a value and return all the keys that have that value? So if I
> have something like:
>
> hashtable.put("A","1");
> hashtable.put("B","1");
> hashtable.put("C","1");
> hashtable.put("D","2");
>
> I could pass in "1" and it would return a Vector or Array with
> "A","B","C" in it? Thanks for any help in advance.


Uh...

switch "key" and "value" in your description, and
org.apache.commons.collections.MultiHashMap does exactly what you want.
 
Reply With Quote
 
 
 
 
Lothar Kimmeringer
Guest
Posts: n/a
 
      05-11-2004
On 11 May 2004 09:03:00 -0700, Nathan Bragg wrote:

> Is there a way using a Hashtable, or some other object to give the
> object a value and return all the keys that have that value? So if I
> have something like:
>
> hashtable.put("A","1");
> hashtable.put("B","1");
> hashtable.put("C","1");
> hashtable.put("D","2");
>
> I could pass in "1" and it would return a Vector or Array with
> "A","B","C" in it? Thanks for any help in advance.


Nothing like that exists with the standard-classes being
provided with the collection-framework. But you easily
can implement your own Map that way with extending from
HashMap and overwriting put/remove:

public Object put(Object key, Object o){
super.put(key, o);
List l = (List) myValMap.get(o);
if (l == null){
l = new LinkedList();
myValMap.put(o, l);
}
l.add(key);
}

This is just to be regarded as hint. You have to
cope with changing and removing values.


Regards, Lothar
--
Lothar Kimmeringer E-Mail: http://www.velocityreviews.com/forums/(E-Mail Removed)
PGP-encrypted mails preferred (Key-ID: 0x8BC3CD81)

Always remember: The answer is forty-two, there can only be wrong
questions!
 
Reply With Quote
 
Roedy Green
Guest
Posts: n/a
 
      05-11-2004
On 11 May 2004 09:03:00 -0700, (E-Mail Removed) (Nathan Bragg)
wrote or quoted :

>hashtable.put("A","1");
>hashtable.put("B","1");
>hashtable.put("C","1");
>hashtable.put("D","2");


you would need to create a second Hashtable with the value as key.
Hashtable won't let you have duplicate keys, you so you need to create
a array[] object when there are dups, and keep replacing it with a
bigger array every time. You could use ArrayLists as your values.

Here is some code that does that sort of thing:

package com.mindprod.replicator;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.regex.Pattern;

/**
* This class is similar to java.util.Properties.
* The properties file has a similar key=value format.
* However, for MultiProperties,
* spaces in the values are not coded
* as "\ ", just as plain " ".
* Values can be a tuple separated by commas.
* The inherited Hashtable get returns a String[].
* There is no support for extended chars such as \n.
* There is no support for \ as a continuation character.
* Comment lines begin with #.
* Blank lines are ignored.
* The file must end with a line separator.
* All values are trimmed of leading and trailing spaces.
* All Strings are interned, so they behave just like
* hard-coded String static finals.
*
* It is basically just a Hashtable with a load method
* and a few conveniences added to the get method.
*
* @author Roedy Green
* @version 1.0
* @since 2003-08-03
*/
public class MultiProperties extends Hashtable
{

/**
* true if you want the debugging harness
*/
private static final boolean DEBUG=false;

/**
* Constructs a new, empty hashtable with
* the specified initial
* capacity and the specified load factor.
* See http://mindprod.com/jgloss/hashtable.html
* for a full description of
* what the initialCapacity and loadFactors mean.
*
* @param initialCapacity the initial capacity of the
hashtable.
* @param loadFactor the load factor of the hashtable.
* @exception IllegalArgumentException if the initial capacity is
less
* than zero, or if the load factor is nonpositive.
*/
public MultiProperties ( int initialCapacity, float loadFactor )
{
super( initialCapacity, loadFactor );
}

/**
* Load the properties hashtable
* from a text file of key=value pairs.
*
* @param in where to load the textual key=value pairs from.
* @exception IOException
*/
public void load ( InputStream in ) throws IOException
{
BufferedReader br = new BufferedReader( new InputStreamReader(
in ) );

while ( true )
{
String line = br.readLine();
if ( line == null )
{
/* eof */
break;
}
if ( line.startsWith( "#" ) )
{
/* ignore comments */
continue;
}
line = line.trim();
if ( line.length() == 0 )
{
/* ignore blank lines */
continue;
}

// split line into key and value
String[] keyValue = keyValueSplitter.split( line );
switch ( keyValue.length )
{
case 1:
{
// key=nothing
String key = keyValue[0].trim().intern();
if ( key.length() == 0 )
{
complain( line );
}
this.put( key, dummy );
}
break;

case 2:
{
// key=value
String key = keyValue[0].trim().intern();
if ( key.length() == 0 )
{
complain( line );
}
// Split value into subfields
String[] values = subFieldSplitter.split(
keyValue[1].trim() );

// trim the multiple values
for ( int i=0; i<values.length; i++ )
{
values[i] = values[i].trim().intern();
}
// save in the underlying Hashtable.
this.put ( key, values );
}
break;

default:
case 0:
complain( line );
}
} // end while
br.close();
} // end load

/**
* Complain about malformed data.
*
* @param line Line of key=value that has a problem.
*/
private static void complain ( String line )
{
throw new IllegalArgumentException( "MultiProperties: malformed
key=value : "
+ line );
}

/**
* Get values associated with key.
*
* @param key Key, case sensitive.
*
* @return array of associated Strings, possibly dimension 0.
* If key is undefined returns empty array, not null.
*/
public String[] getMultiple ( String key )
{
String[] value = (String[]) get( key );
if ( value == null )
{
return dummy;
}
else
{
return value;
}
}

/**
* Get value associated with key.
*
* @param key Key, case sensitive.
* @param defaultValue
* Value for the default if the key is not defined.
* key=nothing returns "", not the default value.
* @return String for a single value, or the first of a set of
multiple values, or "".
*/
public String get ( String key, String defaultValue )
{
Object value = get( key );
if ( value == null )
{
return defaultValue.intern();
}
else
{
String[] array = ((String[])value);
if ( array.length != 0 )
{
return array[0];
}
else
{
return ""; // not defaultValue!
}
}
}

/**
* Get single integer value associated with key.
*
* @param key Key, case sensitive.
* @param defaultValue
* Value for the default if the key is not defined.
* @return integer value of the key, or defaultValue if not defined
or if key=
* @exception NumberFormatException
* if the value is not a valid integer.
*/
public int getInt ( String key, int defaultValue ) throws
NumberFormatException
{
Object value = get( key );
if ( value == null )
{
return defaultValue;
}
else
{
String[] array = ((String[])value);
if ( array.length != 0 )
{
return Integer.parseInt ( array[0] );
}
else
{
return defaultValue;
}
}

}

/**
* Get boolean value associated with key.
* Valid values for key are true, false, yes, no, case insensitive.
*
* @param key Key, case sensitive.
* @param defaultValue
* Value for the default if the key is not defined.
* @return boolean value of the key, or defaultValue if not defined
or if key=
*/
public boolean getBoolean ( String key, boolean defaultValue )
{
Object value = get( key );
if ( value == null )
{
return defaultValue;
}
else
{
String[] array = ((String[])value);
if ( array.length != 0 )
{
return array[0].equalsIgnoreCase( "true" ) ||
array[0].equalsIgnoreCase( "yes" );
}
else
{
return defaultValue;
}
}

}

/**
* A dummy empty array of Strings.
* No point is allocating a fresh one every time it is needed.
*/
private static String[] dummy = new String[ 0 ];

// Pattern to split line into key and value at the =
private static Pattern keyValueSplitter = Pattern.compile ( "=" );

/**
* Pattern to split into words separated by commas.
* Two commas in a row in the String to be matched gives an empty
field
*/
private static Pattern subFieldSplitter = Pattern.compile ( "," );

/**
* test harness
*
* @param args not used
*/
public static void main ( String[] args )
{
if ( DEBUG )
{
MultiProperties m = new MultiProperties ( 100, .75f );
try
{
m.load( new FileInputStream ( "replicator.properties" ) );
}
catch ( IOException e )
{
Persist.fatal( "Unable to read replicator.properties
file."
+ "\n"
+ e.getMessage() );
}
for ( Enumeration e = m.keys(); e.hasMoreElements(); )
{
String key = (String) e.nextElement();
String[] values = m.getMultiple( key );
System.out.println( key + " =");
for ( int i=0; i<values.length; i++ )
{
System.out.println ( values[i] );
}
} // end for
} // end if DEBUG
} // end main
} // end MultiProperties


--
Canadian Mind Products, Roedy Green.
Coaching, problem solving, economical contract programming.
See http://mindprod.com/jgloss/jgloss.html for The Java Glossary.
 
Reply With Quote
 
Roedy Green
Guest
Posts: n/a
 
      05-11-2004
On Tue, 11 May 2004 20:59:09 GMT, Roedy Green
<(E-Mail Removed)> wrote or quoted :

>Here is some code that does that sort of thing:

here is some more
// com.mindprod.pim.PIMEngine.java

package com.mindprod.pim;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.TreeMap;

/**
* Engine for a ram-based Personal Information Manager.
* Internally it has a HashMap of Items and a TreeMap of Keys.
* Each key can point directly to several Items, and each Item can
point to several keys.
* @author copyright (c) 1999-2004 Roedy Green, Canadian Mind
Products
* may be copied and used freely for any purpose but military.
*
* Roedy Green
* Canadian Mind Products
* #327 - 964 Heywood Avenue
* Victoria, BC Canada V8V 2Y5
* tel: (250) 361-9093
* (E-Mail Removed)
* http://mindprod.com
*
* version 1.0 1999 October 12 8:30 PM -- 9:30 PM
* version 1.1 1999 October 13 - 9:30 PM -- 12:20 PM
* - clean compile of code, no testing.
* - no pickle
* version 1.2 1999 October 13 - 9:10 AM -- 10:10 AM
* - add find all strings for item
* - add sort to keep Keys per item in
order
* - remove requirement for makeUnique.
* - get rid of compiler errors
* - deal with null initial case in
addKey and addItem
* version 1.3 1999 October 13 - 10:40 AM -- 11:15 AM
* - make allKeys use String -> key
consistently.
* - crude test of add/display functions.
* version 1.4 1999 October 13 - 2:20 PM -- 3:20 PM 7:00 PM -- 8:00
PM
* - add pickle/reconstitute
* - only sort keyList just prior to
display to save overhead
* of repeated sorts during
reconstitution.
* - change constructor to take String
instead of File.
* - add showAll debug tool
* - clone rather than give access to
internal array in find.
*
*/
public class PIMEngine implements java.io.Serializable
{

/**
* public constructor.
* @param modelName is a filename less the .pim extension where the
PIM data are stored,
* e.g. "C:\\myDir\\plays"
*/
public PIMEngine(String modelName) throws IOException,
FileNotFoundException {
this.modelName = modelName;
this.load();
} // end constructor

/**
* load a previously saved pickled version of the entire data
structure.
*/
public void load() throws IOException {
File current = new File(modelName + ".pim");
if ( current.exists() )
{
// O P E N
try
{
FileInputStream fis = new FileInputStream(current);
BufferedInputStream bis = new BufferedInputStream(fis,
4096 /* buffsize */);
ObjectInputStream ois = new ObjectInputStream(bis);
// R E A D
// reconstitute fields individually rather than
// "this" because of readObject/writeObject asymmetry
allKeys = (TreeMap) ois.readObject();
// restore transient fields, namely the allItems HashMap
and the
// Item.keyList[] back pointers.
allItems = new java.util.HashMap();
// enumerate all the Key objects in the TreeMap
Collection keys = allKeys.values();
Iterator eachKey = keys.iterator();
while ( eachKey.hasNext() )
{
Key key = (Key)eachKey.next();
int numItems = key.itemList.length;
for ( int i=0; i<numItems; i++ )
{
// itemList[i] is already unique, we use makeUnique
for the side effect
// of adding the item to the allItems HashMap
Item item = makeUnique(key.itemList[i]);
// build item.keyList[] back pointer
item.addKey(key);
} // end for
} // end while
// C L O S E
ois.close();
}
catch ( ClassNotFoundException e )
{
throw new IOException("PIM file corrupt");
}
catch ( OptionalDataException e )
{
throw new IOException("PIM file corrupt");
}
catch ( IOException e )
{
throw new IOException("PIM file corrupt");
}
}
else
{
// starting from scratch
allKeys = new java.util.TreeMap();
allItems = new java.util.HashMap();
}
} // end load

/**
* save the entire data structure in pickled form in a file.
* @param File to store program state in pickled form.
*/
public void save() throws IOException {
// rename old, as .old save as .pim
File prev = new File(modelName + ".old");
File current = new File(modelName + ".pim");;
prev.delete();
current.renameTo(prev);
// O P E N
FileOutputStream fos = new FileOutputStream(current);
BufferedOutputStream bos = new BufferedOutputStream(fos, 4096 /*
buffsize */);
ObjectOutputStream oos = new ObjectOutputStream(bos);
// W R I T E
// pickle fields individually rather than
// "this" because of readObject/writeObject asymmetry
// Write out the allKeys TreeMap but leave behind the allItems
HashMap
// Also leave out the Key[] Item.KeyList back pointers.
oos.writeObject(allKeys);
// C L O S E
oos.close();
} // end save

/**
* create an association between the given key and the given item.
* Items may have many associated keys, and keys may associate to
many items.
* @param keystring key for the association
* @param item data object derived from Item class.
*/
public void add(String keyString, Item item)
{
Item uniqueItem = makeUnique(item);
Key key = lookup(keyString);
if ( key == null )
{
key = new Key(keyString);
allKeys.put(keyString, key);
}
key.addItem(uniqueItem);
uniqueItem.addKey(key);
} // end add

/**
* create an association between the given list of keys and the
given item.
* Items may have many associated keys, and keys may associate to
many items.
* @param keystring list of keys for the association
* @param item data object derived from Item class.
*/
public void add(String[] keyString, Item item)
{
Item uniqueItem = makeUnique(item);
int numKeyStrings = keyString.length;
for ( int i=0; i<numKeyStrings; i++ )
{
add(keyString[i], uniqueItem);
} // end for
} // end add

/**
* Break an existing association between a key and an item.
* This will not destroy either the key or the item, though
* it will remove references to them, which may eventually lead to
* them being garbage collected.
* It is not considered an error to remove a pair that has not
been previously added.
* @param keystring key for the association.
* @param item data object derived from Item class.
*/
public void remove(String keyString, Item item)
{
Item uniqueItem = makeUnique(item);
Key key = lookup(keyString);
if ( key == null )
{
// was no such keyString
return;
}
key.removeItem(uniqueItem);
if ( key.itemList == null )
{
allKeys.remove(key.keyString);
}
uniqueItem.removeKey(key);
if ( uniqueItem.keyList == null )
{
allItems.remove(uniqueItem);
}
} // end remove

/**
* Break an existing association between a list of keys and an
item.
* This will not destroy either the key or the item, though
* it will remove references to them, which may eventually lead to
* them being garbage collected.
* It is not considered an error to remove a pair that has not
been previously added.
* @param keystring list of keys for the association.
* @param item data object derived from Item class.
*/
public void remove(String[] keyString, Item item)
{
Item uniqueItem = makeUnique(item);
int numKeyStrings = keyString.length;
for ( int i=0; i<numKeyStrings; i++ )
{
remove(keyString[i], uniqueItem);
}
} // end remove

/**
* Break all existing associations between the given key and any
items.
* This will not destroy either the key or the item, though
* it will remove references to them, which may eventually lead to
* them being garbage collected.
* It is not considered an error to remove a key that has not been
previously added.
* @param keystring key to remove.
*/
public void remove(String keyString)
{
Key key = lookup(keyString);
if ( key == null )
{
// was no such keyString
return;
}
int numItems = key.itemList.length;
for ( int i=0; i<numItems; i++ )
{
Item item = key.itemList[i];
item.removeKey(key);
if ( item.keyList == null )
{
allItems.remove(item);
}
} // end for
key.itemList = null;
allKeys.remove(key.keyString);
} // end remove

/**
* Break all existing associations between the given item and all
associated keys.
* This will not destroy either the key or the item, though
* it will remove references to them, which may eventually lead to
* them being garbage collected.
* It is not considered an error to remove a key that has not been
previously added.
* @param item data object derived from Item class.
*/
public void remove(Item item)
{
Item uniqueItem = makeUnique(item);
int numKeys = uniqueItem.keyList.length;
for ( int i=0; i<numKeys; i++ )
{
Key key = uniqueItem.keyList[i];
key.removeItem(uniqueItem);
if ( key.itemList == null )
{
allKeys.remove(key.keyString);
}
} // end for
uniqueItem.keyList = null;
allItems.remove(uniqueItem);
} // end remove

/**
* Find all items associated with the given key.
* @param keyString the string to lookup by.
*/
public Item[] find(String keyString)
{
Key key = lookup(keyString);
if ( key == null )
{
System.out.println("lookup fail");
return null;
}
Item[] itemList = key.itemList;
if ( itemList == null )
{
return null;
}
int numItems = itemList.length;
// can't use Item[].clone because it is protected.
Item[] clonedItemList = new Item[numItems];
System.arraycopy(itemList, 0, clonedItemList, 0, numItems);
return clonedItemList;
} // end find

/**
* Find all KeyStrings associated with the given item
* @param item data object derived from Item class.
* @return array of Strings representing associated keys.
*/
public String[] find(Item item)
{
Item uniqueItem = makeUnique(item);
Key[] keyList = uniqueItem.keyList;
if ( keyList == null )
{
return null;
}
// put in alphabetical order, preparatory to display
Arrays.sort(keyList);
int numKeyStrings = keyList.length;
String[] keyStringList = new String[numKeyStrings];
for ( int i=0; i<numKeyStrings; i++ )
{
keyStringList[i] = keyList[i].keyString;
}
return keyStringList;
} // end find

/**
* Ensure the Item is unique by returning a reference to the master
version which
* already lives in the allKeys HashTable. If the Item has never
been seen before,
* it is added to the HashTable.
* @param item data object derived from Item class.
*/
public Item makeUnique(Item item)
{
Item uniqueItem = (Item) allItems.get(item);
if ( uniqueItem != null )
{
return uniqueItem;
}
uniqueItem = item;
allItems.put(uniqueItem, uniqueItem);
return uniqueItem;
}

/**
* lookup the given Keystring to find the associated Key object.
* @param keyString the lookup string.
* @return Key object, or null if not found.
*/
private Key lookup(String keyString)
{
return(Key) allKeys.get(keyString);
} // end lookup

/**
* Lookup structure keys -> Items.
* Access either directy by key or by alphabetic order.
* indexed by KeyString, gives Key, which then points to Items.
*/
protected java.util.TreeMap allKeys;

/**
* Lookup structure data contents -> Item.
* Only used internally. Helps prevent duplicate Items.
* indexed by Item, gives Item, which then points to assocated Keys
which then give keyStrings.
*/
transient protected java.util.HashMap allItems;

/**
* the filename, without .pim extension where the model is stored,
in pickled form.
*/
transient protected String modelName;

/**
* debugging tool that displays all the Key and Item objects.
*/
public void showAll()
{
if ( true )
{
if ( allKeys != null )
{
System.out.println("BY KEY");
Collection keys = allKeys.values();
Iterator eachKey = keys.iterator();
while ( eachKey.hasNext() )
{
Key key = (Key)eachKey.next();
System.out.println("key " + key.keyString);
if ( key.itemList != null )
{
int numItems = key.itemList.length;
for ( int i=0; i<numItems; i++ )
{
TextItem item = (TextItem) key.itemList[i];
System.out.println(" item " + item.getText());
} // end for
} // if
} // end while
} // end if allKeys
if ( allItems != null )
{

System.out.println("BY ITEM");
Collection items = allItems.values();
Iterator eachItem = items.iterator();
while ( eachItem.hasNext() )
{
TextItem item = (TextItem)eachItem.next();
System.out.println("item " + item.getText());
String [] keyStrings = find(item);
if ( keyStrings != null )
{
int numKeyStrings = keyStrings.length;
for ( int j=0; j<numKeyStrings; j++ )
{
System.out.println(" key " + keyStrings[j]);
} // end for
} // end if
} // end while
} // end if allItems
} // end if

} // end showAll

public static void main (String[] args)
{
try
{
PIMEngine p = new PIMEngine("C:\\temp\\temp1");
Item t1 = new TextItem("Love's Labour Lost");
Item t2 = new TextItem("The Tempest");
Item t3 = new TextItem("Macbeth");
Item t4 = new TextItem("The Tempest");
Item t5 = new TextItem("Duncan the Wonder Dog");
p.add("Duncan",t3);
p.add("Duncan",t5);
p.add("Banquo",t3);
p.add("Ariel",t4);
System.out.println("corresponding keys to item Macbeth");
String[] foundKeyStrings = p.find(t3);
if ( foundKeyStrings != null )
{
for ( int i=0; i<foundKeyStrings.length; i++ )
{
System.out.println(foundKeyStrings[i]);
}
}

System.out.println("corresponding items to key Duncan");
Item[] foundItems = p.find("Duncan");
if ( foundItems != null )
{
for ( int i=0; i<foundItems.length; i++ )
{

System.out.println(((TextItem)foundItems[i]).getText());
}
}
p.showAll();
p.save();
}
catch ( IOException e )
{
System.out.println(e);
}

} // end main

} // end class PIMEngine

------------------

// com.mindprod.pim.Item.java
package com.mindprod.pim;

/**
* Base class to represent an data item in the PIM. It might
represent a
* URL, the name of file, a hunk of text, a GIF, etc. Different items
types
* would hold different types of data. All Item types are derived
from this
* base class.
*/
public abstract class Item implements java.io.Serializable
{
/**
* List of associated Key objects, not key Strings.
* Put in alphabetical order, just prior to display, but otherwise
we allow it to
* be in any order.
* Array is compact even if a bit clumsy to add and remove an
element.
* We don't include this in the pickle, because the recursion could
overflow
* the stack. PIMEngine.load reconstitutes these, not
Item.readObject.
*/
transient protected Key[] keyList;

/**
* add given key to the keylist if it is not already there.
*/
protected void addKey(Key key)
{
int len;
if ( keyList == null )
{
len = 0;
}
else
{
len = keyList.length;
}
for ( int i=0; i<len; i++ )
{
// since unique, can use == instead of equals.
if ( key == keyList[i] )
{
// already in list
return;
}
} // end for
// grow the array to make room to add item at the end
Key[] newKeyList = new Key[len+1];
if ( len > 0 )
{
System.arraycopy(keyList, 0, newKeyList, 0, len);
}
newKeyList[len] = key;
// allow to get out of alphabetical order
keyList = newKeyList;
} // end addKey

/**
* remove given key from the keylist.
* If it is already removed, that's ok.
*/
protected void removeKey(Key key)
{
int len = keyList.length;
for ( int i=0; i<len; i++ )
{
// since unique, can use == instead of equals.
if ( key == keyList[i] )
{
// found in list
if ( len == 1 )
{
keyList = null;
return;
}
// shrink the array to remove ith element
Key[] newKeyList = new Key[len-1];
// copy elts below i, if any
if ( i > 0 )
{
System.arraycopy(keyList, 0, newKeyList, 0, i);
}
// copy elts above i, if any
int upper = len-i;
if ( upper > 0 )
{
System.arraycopy(keyList, i+1, newKeyList, i, upper);
}
keyList = newKeyList;
// won't disturb sort order
return;
} // end if
} // end for
// not in list, nothing to do
} // end removeKey

/**
* Returns a hashcode based solely on the data contents of the
Item, not the keylist.
*
* @return a hash code value for this object.
*/
public abstract int hashCode();

/**
* Compares two Items, basing equality on the data contents of the
Item, not the keylist.
* @param anObject other Item to compare to.
* @return true if the Items are equal. Return false if anObject is
not of the same type.
*/
public abstract boolean equals(Object anObject);

} // end class Item

----------------

// com.mindprod.pim.Key.java
package com.mindprod.pim;

/**
* The Key our lookup engine works with in the TreeMap. It points to
several Items.
*/
public final class Key implements Comparable, java.io.Serializable
{

/**
* public constructor
*/
public Key (String keyString)
{
this.keyString = keyString;
this.itemList = null;
} // end constructor

/**
* the lookup key
*/
protected String keyString;

/**
* List of associated Items
* Array is compact even if a bit clumsy to add and remove an
element.
*/
protected Item[] itemList;

/**
* Returns a hashcode based solely on the lookup key, not the
items.
*
* @return a hash code value for this object.
*/
public int hashCode()
{
return keyString != null ? keyString.hashCode(): 0;
}

/**
* Compares two Keys, basing equality on the key, not the Itemlist.
* @param anObject other Item to compare to.
* @return true if the Items are equal. Return false if anObject is
not of the same type.
*/
public boolean equals(Object anObject)
{
if ( keyString == null ) return false;
if ( anObject instanceof Key )
{
return this.keyString.equals(((Key)anObject).keyString);
}
if ( anObject instanceof String )
{
return this.keyString.equals((String)anObject);
}
return false;
} // end equals

/**
* add an Item to the ItemList if it is not already there.
* @param Item to add, must be unique.
*/
protected void addItem(Item uniqueItem)
{
int len;
if ( itemList == null )
{
len = 0;
}
else
{
len = itemList.length;
}
for ( int i=0; i<len; i++ )
{
// since unique, can use == instead of equals.
if ( uniqueItem == itemList[i] )
{
// already in list
return;
}

} // end for
// grow the array to make room to add item at the end
Item[] newItemList = new Item[len+1];
int below = len;
if ( below > 0 )
{
System.arraycopy(itemList, 0, newItemList, 0, below);
}
newItemList[len] = uniqueItem;
itemList = newItemList;
// order does not matter
} // end addItem

/**
* remove given item from this key's itemList.
* If it is already removed, that's ok.
*/
protected void removeItem(Item uniqueItem)
{
int len = itemList.length;
for ( int i=0; i<len; i++ )
{
// since unique, can use == instead of equals.
if ( uniqueItem == itemList[i] )
{
// found in list
if ( len == 1 )
{
itemList = null;
return;
}
// shrink the array to remove ith element
Item[] newItemList = new Item[len-1];
// copy elts below i, if any
int below = i;
if ( below > 0 )
{
System.arraycopy(itemList, 0, newItemList, 0, below);
}
// copy elts above i, if any
int above = len-i;
if ( above > 0 )
{
System.arraycopy(itemList, i+1, newItemList, i, above);
}
itemList = newItemList;
// existing order is just fine
return;
} // end if
} // end for
// not in list, nothing to do
} // end removeItem

/* compares this Key's Keystring to another's.
* @param o Key to be compared with this one.
* @return +ve if this one is bigger, 0 if equal, -ve if smaller.
*/
public int compareTo (Object o) throws ClassCastException
{
return this.keyString.compareTo(((Key)o).keyString);
}

/**
* @return a String that represents this Key
*/
public String toString()
{
return keyString;
}

} // end class Key

--------------------

// com.mindprod.pim.TextItem.java
package com.mindprod.pim;

/**
* Item to associate, holds simple string, without embedded \n chars.
*/

public class TextItem extends Item
{

/**
* public constructor
*/
public TextItem (String text)
{
super();
this.text = text;
} // end constructor

/**
* text data to be associated with keys
*/
private String text;

/**
* get text data string for this TextItem
* Note there is no corresponding setText, since the data must be
immutable.
* @return text string.
*/
public String getText()
{
return text;
} // end getText

/**
* @return a String that represents this TextItem
*/
public String toString()
{
return text;
}

/**
* Returns a hashcode based solely on the data contents of the
Item, not the keylist.
*
* @return a hash code value for this object.
*/
public int hashCode()
{
return text.hashCode();
}

/**
* Compares two Items, basing equality on the data contents of the
Item, not the keylist.
* @param anObject other Item to compare to.
* @return true if the Items are equal. Return false if anObject is
not of the same type.
*/
public boolean equals(Object anObject)
{
if ( text == null ) return false;
if ( anObject instanceof TextItem )
{
return text.equals(((TextItem)anObject).text);
}
if ( anObject instanceof String )
{
return text.equals((String)anObject);
}
return false;
} // end equals

} // end class TextItem

-------------------

I have two other variants, one uses a TreeMap and one supports Many to
One mappings, not many to many.




--
Canadian Mind Products, Roedy Green.
Coaching, problem solving, economical contract programming.
See http://mindprod.com/jgloss/jgloss.html for The Java Glossary.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: hashtable or map? (map inserts not behaving as I expect - and I cant find a decent simple example for hashtable) Kai-Uwe Bux C++ 1 12-21-2008 09:25 PM
Hashtable question Steve ASP .Net 3 08-21-2006 07:49 PM
Three-Part HashTable Question Chuck Insight ASP .Net Web Controls 0 03-10-2005 11:43 PM
Problem with hashTable Guillermo Perl 1 03-04-2004 12:43 PM
vbc compilation fails when using Hashtable Jonathan Wolfson ASP .Net 1 06-27-2003 04:40 PM



Advertisments