Searching a hash by two different criteria?

P

Paul Tomblin

I have these objects that I want to put into a hash, and then be able to
pull them out based on either of two criteria, both Strings. So what I've
done is to make a Key class that has both of the Strings in it, and the
"equals" method on the Key class will return true if one String is
non-null and equals the one in the other Key, or if the other String is
non-null and equals the one in the other Key.

Is that sufficient, or should I make the Key implement Comparable or
something?


/**
* Key allows the object in the cache to be searched for by UUID *or*
* by fileName.
*/
private class Key
{
String fileName;
String UUID;
public boolean equals(Object obj)
{
if (obj instanceof Key)
{
Key otherKey = (Key)obj;
if (UUID != null && otherKey.UUID != null)
{
return UUID.equals(otherKey.UUID);
}
if (fileName != null && otherKey.fileName != null)
{
return fileName.equals(otherKey.fileName);
}
}
return false;
}
}
 
J

John C. Bollinger

Paul said:
I have these objects that I want to put into a hash, and then be able to
pull them out based on either of two criteria, both Strings. So what I've
done is to make a Key class that has both of the Strings in it, and the
"equals" method on the Key class will return true if one String is
non-null and equals the one in the other Key, or if the other String is
non-null and equals the one in the other Key.

Is that sufficient, or should I make the Key implement Comparable or
something?

The idea is completely broken. You are ignoring the fact that the keys'
hashcodes are of primary importance when storing values in a hash-based
Map. Their equality to each other is relevant only in comparing two key
objects with the same hash code. It is essential for correct operation
of the standard Hash-based maps that keys' equals() methods be
"consistent" with their hashCode() methods, which means that if two keys
are equal to each other then they must have the same hash code. (The
reverse might not be true, and generally cannot be guaranteed.) The
only way your key class' equals() method could be consistent with its
hashCode() method would be if the hashCode() method returned the same
value for all instances; needless to say, that would remove all value of
using instances as hash keys.

The correct solution is to maintain two maps, one for each lookup criterion.
 
P

Paul Tomblin

In a previous article said:
The idea is completely broken. You are ignoring the fact that the keys'
hashcodes are of primary importance when storing values in a hash-based

Yeah, I just realized that about 5 seconds ago, and was about to post a
"never mind".
The correct solution is to maintain two maps, one for each lookup criterion.

Thanks for confirming it. Dammit. That means I can't use the LRU
functions in LinkHashMap either, because something will fall off of one
Map but not the other.

It also turns out that extracting the fileName and UUIDs from the cached
objects is problematic as well, so I'm going to have to put an object that
consists of the fileName, the UUID, and the object I was going to cache
into each Map so that I can get the UUID given the fileName and vice versa.
 
I

Ingo R. Homann

Hi John,
Paul said:
I have these objects that I want to put into a hash, and then be able to
pull them out based on either of two criteria, both Strings. So what
I've
done is to make a Key class that has both of the Strings in it, and the
"equals" method on the Key class will return true if one String is
non-null and equals the one in the other Key, or if the other String is
non-null and equals the one in the other Key.

Is that sufficient, or should I make the Key implement Comparable or
something?


The idea is completely broken.
[better idea]

I think, your idea is indeed better and "cleaner".

But of course two maps need more memory for the references stored
inside. Also, searching in two maps takes more time than searching in
one map.

If that is a problem, Pauls idea might work as well (if I understand him
correctly), if the Keys hashCode-method is implemented right. I think,
the following should work:

public int hashCode() {
if(UUID!=null) {
return UUID.hashCode()*2;
} else {
return filename.hashCode()*2+1;
}
}

This is consistent with the rule "equals -> same hashCode" and I guess,
it will also be a "good" hashCode (in the way that different objects
should have different hashcodes when possible).

Ciao,
Ingo
 
P

Paul Tomblin

In a previous article said:
If that is a problem, Pauls idea might work as well (if I understand him
correctly), if the Keys hashCode-method is implemented right. I think,
the following should work:

public int hashCode() {
if(UUID!=null) {
return UUID.hashCode()*2;
} else {
return filename.hashCode()*2+1;
}
}

No, this won't help me find objects in the Map that have both UUID and
fileName set when I only have one of the values.

I'm afraid I'm stuck with two Maps, and also implementing my own LRU size
limitations.
 
I

Ingo R. Homann

Hi Paul,

Paul said:
No, this won't help me find objects in the Map that have both UUID and
fileName set when I only have one of the values.

Ah, OK, I thought, only one of the two keys will be set, and never both.

Now, two maps seem to be the only solution.

Ciao,
Ingo
 
M

Marcin Grunwald

Paul said:
Yeah, I just realized that about 5 seconds ago, and was about to post a
"never mind".


Thanks for confirming it. Dammit. That means I can't use the LRU
functions in LinkHashMap either, because something will fall off of one
Map but not the other.

It also turns out that extracting the fileName and UUIDs from the cached
objects is problematic as well, so I'm going to have to put an object that
consists of the fileName, the UUID, and the object I was going to cache
into each Map so that I can get the UUID given the fileName and vice
versa.


MultiKeyMap should help:
http://jakarta.apache.org/commons/c...ache/commons/collections/map/MultiKeyMap.html

and
MultiKeyMap.decorate(new LRUMap()) creates an least recently used map.
 

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,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top