Hashtable question

N

Nathan Bragg

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
 
M

Michael Borgwardt

Nathan said:
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.
 
L

Lothar Kimmeringer

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: (e-mail address removed)
PGP-encrypted mails preferred (Key-ID: 0x8BC3CD81)

Always remember: The answer is forty-two, there can only be wrong
questions!
 
R

Roedy Green

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 = values.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 );
}
} // end for
} // end if DEBUG
} // end main
} // end MultiProperties
 
R

Roedy Green

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
* mailto:[email protected]
* 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 is already unique, we use makeUnique
for the side effect
// of adding the item to the allItems HashMap
Item item = makeUnique(key.itemList);
// 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, 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, 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;
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;
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 = keyList.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;
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);
}
}

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).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 )
{
// 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 )
{
// 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 )
{
// 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 )
{
// 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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top