Sort a Hashtable - Check my code Plz!

Hi All,
I am trying to sort a Hashtable based on the value of the keys in tha hashtable. I wrote a Java Service for that and here it is…
[highlight=java]
IDataCursor idcPipeline = pipeline.getCursor();

IDataCursor pipelineCursor_1 = pipeline.getCursor();
Hashtable ht;
if (idcPipeline.first(“Hashtable”))
{
ht = (Hashtable)idcPipeline.getValue();
}
else
{
throw new ServiceException(“Hashtable is null!”);
}
Vector v = new Vector(ht.keySet());
Collections.sort(v);
Iterator it = v.iterator();
String strKey = “”;
Hashtable h = new Hashtable();
while (it.hasNext())
{
strKey = it.next().toString();
Object str = ht.get(strKey);
h.put(strKey, str);
}
pipelineCursor_1.insertAfter(“SortedHashtable”, h);
idcPipeline.destroy();
pipelineCursor_1.destroy();[/highlight]

This works in eclipse, but when I run it in developer, I get the original un-sorted Hashtable back…am I missing something?

Thank you,
Zafar.

The order of the entries in a hashtable is not defined. There is no intrinsic order of the entreis in a hashtable. Calling hashtable.put(key,value) and passing keys in order does not preserve that order.

You’ve undoubtedly come across information on the web about “sorting hashtables” but none of them show how to sort a hashtable. They show how to extract data from the hashtable (either the keys or the values), put that data into another data structure (e.g. ArrayList, Vector, etc.) and sort that structure, not the hashtable.

When you say it “works in Eclipse” what exactly do you mean?

If you need a sorted list of key/value pairs you need to use a different class, such as TreeMap or other class that either implicitly maintains a sorted order (TreeMap does so) or can be ordered (e.g. Vector).

Java service code-wise, you have two cursors open on the pipeline. Not an issue per se, but unnecessary. You also leave both cursors open when you throw the ServiceException, which is poor housekeeping.

Java 101…Hashtable can’t be sorted. Thx for setting me right on that one.
I use Eclipse IDE to write all my java services and when I create a hashtable in it and do what I was trying to do it, the results always were sorted.
Basically, I was doing this, create the hashtable, insert key value pairs in it, extract the keyset into a vector, sort the vector, and iterate over the vector and for each key in vector, get the value from old hashtable and put em both in the new hashtable and print it out. When I did this in eclipse, the hashtable was always sorted. That’s what I meant by " it works in Eclipse". I donno why and how it is…but it works.

Now coming to the issue at hand…does anyone have an idea of how to implement a treemap in webMethods? I am going to give that a shot here…but if someone has already done it, please let me know.

Thanks Rob!!!

-Z

Thanks to Rob’s suggestion…I was able to solve my problem
Here is the working code if anyone needs it…
Break it and let me know …so I can make it robust.
[highlight=java]IDataCursor idcPipeline = pipeline.getCursor();
//Read Hashtable
Hashtable ht;
if (idcPipeline.first(“Hashtable”))
{
ht = (Hashtable)idcPipeline.getValue();
}
else
{
throw new ServiceException(“Hashtable is null!”);
}

//Read keyset from Hashtable into a Vector
Vector v = new Vector(ht.keySet());
//Sort the vector
Collections.sort(v);
Iterator it = v.iterator();
String strKey = “”;
//Create a new TreeMap to store the sorted Hashtable values.
TreeMap h = new TreeMap();
while (it.hasNext())
{
strKey = it.next().toString();
Object str = ht.get(strKey);
h.put(strKey, str);
}
IDataUtil.put(idcPipeline, “SortedHashtable”, h);
idcPipeline.destroy();[/highlight]

-Z

Glad that the feedback helped.

I would suggest changing the name of the output variable from “SortedHashtable” to “map” or “TreeMap” or something since the object in the pipeline isn’t a hashtable, it’s a treemap.

You’re effectively sorting your list twice. Once in the vector and again when inserting into the TreeMap. And since Hashtable implements the Map interface and the TreeMap constructor accepts a Map, you can greatly simplify your code:
[highlight=java]
IDataCursor idcPipeline = pipeline.getCursor();
//Read Hashtable
Hashtable ht;
if (idcPipeline.first(“Hashtable”))
{
ht = (Hashtable)idcPipeline.getValue();
}
else
{
idcPipeline.destroy();
throw new ServiceException(“Hashtable is null!”);
}

// Create a new TreeMap, using the entries from
// the hashtable. TreeMap maintains order.
IDataUtil.put(idcPipeline, “TreeMap”, new TreeMap(ht));

idcPipeline.destroy();[/highlight]

That’s a good Idea. Thanks for the modifications Rob!
I am suddenly faced with a problem…This does not sort -ve numbers and also, say if the HashTable is {1=abcsdsdq, -5=fed, -1=gre, 45=abcsfdsw, 5=abcsfdswggdd, 4=abc} the TreeMap looks like this…{-1=gre, -5=fed, 1=abcsdsdq, 4=abc, 45=abcsfdsw, 5=abcsfdswggdd}

Any thoughts?
-Z

I assume that the keys are strings. In this case, the order is in “character code” order (using the ASCII code for each character). So they are sorted, just not in the numeric order you’re expecting.

To put these in numeric order, the hashtable will need to be populated with Integer objects. Or, you can use an anonymous inner-class to compare the strings as numbers. Here’s a sample:
[highlight=java]
java.util.Hashtable h = new java.util.Hashtable();
h.put(“1”, “abcsdsdq”);
h.put("-5", “fed”);
h.put("-1", “gre”);
h.put(“45”, “abcsfdsw”);
h.put(“5”, “abcsfdswggdd”);
h.put(“4”, “abc”);

java.util.TreeMap tm = new java.util.TreeMap(
new java.util.Comparator() {
public int compare(Object o1, Object o2)
{
return ((new Integer((String)o1)).compareTo(new Integer((String)o2)));
}
public boolean equals(Object o1, Object o2)
{
return ((new Integer((String)o1)).equals(new Integer((String)o2)));
}
}
);
tm.putAll(h);
IDataCursor idc = pipeline.getCursor();
IDataUtil.put(idc, “ht”, h);

// You can put tm in the pipeline but it will fail when run in
// Developer because the Comparator isn’t Serializable, which
// is required for the pipeline transmission from IS to Developer
//IDataUtil.put(idc, “tm”, tm);

// Show the order of the keys in string lists
IDataUtil.put(idc, “htkeys”, h.keySet().toArray(new String[h.size()]));
IDataUtil.put(idc, “tmkeys”, tm.keySet().toArray(new String[h.size()]));
idc.destroy();[/highlight]
Hope this helps.

Hey Rob,
That worked like a charm! Thanks a lot!!

Zafar.

Which approach did you take? Integers in the Hashtable?

What process is creating the Hashtable? Might it be advisable to create TreeMap right from the start?