Map that takes a pair of keys?

M

marcus

This is a tough one to google hehe
Is there code available, or a coupla good hints, for a fast map that
takes a pair of keys to produce a value?

I have two keys that together map to a single (non-unique) value, but
not in a particularly logical manner. This is for a personal project
and doesn't have to look pretty, so I can hard-code loading the map.
Pulling the values out, though, I don't want a hundred or so nested if
statements.

Hmm, can I set up a map of maps? the first key returns a value, which
itself is a map of possible second keys? *shudder*
 
M

marcus

Jacob said:
Just bundle the two in a class and use that as your key. huh?



Always try to make your code look pretty. It makes the
programming experience more enjoyable and will give you
good programming habits in the long run.
 
J

Jacob

marcus said:
This is a tough one to google hehe
Is there code available, or a coupla good hints, for a fast map that
takes a pair of keys to produce a value?

Just bundle the two in a class and use that as your key.
This is for a personal project and doesn't have to look pretty, ...

Always try to make your code look pretty. It makes the
programming experience more enjoyable and will give you
good programming habits in the long run.
 
C

Chas Douglass

marcus said:
[snip]
Create a new class that contains both of your keys. Use it as a key in
HashMap.

public class TwoKeys {

private Object key1;
private Object key2;

public TwoKeys(Object key1, Object key2) {
this.key1 = key1;
this.key2 = key2;
}

// getters() and setters() omitted for clarity

}

Refactor the key1 and key2 object types appropriately.

Now you can:

HashMap<TwoKeys, Object> hashMap =
new HashMap<TwoKeys, Object>();
hashMap.put(new TwoKeys(key1, key2), new Object());

Once again, refactor "Object" to be something appropriate for your
application.

(WARNING: code typed on the fly, not guaranteed to compile without typos)

If you want to use one of the ordered collections, you'll need to
implement Comparable in TwoKeys.

Chas Douglass
 
M

marcus

if I create a second object with the same parameters as the first
object, it is a different object and won't pull the same value, will it?
or am I misunderstanding. I was planning on using immutable objects,
like String.
 
O

Oscar kind

Chas Douglass said:
Create a new class that contains both of your keys. Use it as a key in
HashMap.

public class TwoKeys {

private Object key1;
private Object key2;

public TwoKeys(Object key1, Object key2) {
this.key1 = key1;
this.key2 = key2;
}

// getters() and setters() omitted for clarity

}

Refactor the key1 and key2 object types appropriately.

Also don't forget to override both equals() and hashCode().

If you don't, then to retreive a value you need the exact same key
object (or another one at the exact same memory location, as that is
how Object#hashCode() works).

Assuming you use an object like String or a subclass of Number as your
keys (which already override those methods), something like this probably
suffices:

public boolean equals(Object o) {
// An object is always different from null.
if (o == null) {
return false;
}
// The first key is empty, but it's counterpart is not.
if (key1 == null && o.key1 != null) {
return false;
}
// The second key is empty, but it's counterpart is not.
if (key2 == null && o.key2 != null) {
return false;
}
// The first key is not empty, but differs from it's counterpart.
if (key1 != null && !key1.equals(o.key1))
{
return false;
}
// The second key is not empty, but differs from it's counterpart.
if (key2 != null && !key2.equals(o.key2))
{
return false;
}
// Found no differences.
return true;
}

public int hashCode() {
int hash1 = key1!=null ? key1.hashCode() : 0;
int hash2 = key2!=null ? key2.hashCode() : 0;
return hash1 ^ hash2;
}
 
T

Tor Iver Wilhelmsen

Chas Douglass said:
Create a new class that contains both of your keys. Use it as a key in
HashMap.

Note that you will also want to implement equals() and hashCode(),
plus possibly toString() for readability.

The most basic equals() is

return key1.equals(arg.key1)&&key2.equals(arg.key2);
 
M

marcus

Tor, Jacob, Chas --
thanx!
I was just reading up on the use of non-immutable objects in a hashmap
and the key (sick) was implementing an equals method, so I was posting
that I had a baby Eureka moment.

I think I am down to 4 levels of indirection, so all is well.

Cheers!
-- clh
 
M

marcus

Thanx oscar -- that was what I was missing. I have a couple solutions I
am going to benchmark.

question about your code, tho
public boolean equals(Object o) {
// An object is always different from null.
if (o == null) {
return false;
}
// The first key is empty, but it's counterpart is not.
if (key1 == null && o.key1 != null) {
return false;
}
// The second key is empty, but it's counterpart is not.
if (key2 == null && o.key2 != null) {
return false;
}
// The first key is not empty, but differs from it's counterpart.
if (key1 != null && !key1.equals(o.key1))

isn't this last line recursing?
 
O

Oscar kind

marcus said:
question about your code, tho

[cut some lines]
isn't this last line recursing?

No, because it calls equals on a member variable; not on its own object.
The method being called is not the same: it has the same name, but belongs
to another object (unless key1 has the value this).
 
M

marcus

No, because it calls equals on a member variable; not on its own object.
The method being called is not the same: it has the same name, but belongs
to another object (unless key1 has the value this).

thanx -- man I must have some nasty assumptions running around in my
brain about immutables (String, Integer) being just fancy primitives or
something, and I am stuck on hash keys being primitives. Ugh.

Anyhow I solved the problem, and learned a couple things -- so thanx all!
 
C

Chris Riesbeck

bugbear said:
Yes.

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

Java may or may not be a great language, But the library support
is kinda' handy. Learn to use it.

The Jakata Commons packages are handy but not official Java, are they?

No one mentioned using ArrayList's as the keys. They already implement
equals() and hashCode() correctly. E.g.,

public class MultiKeyMap extends HashMap {

List key = newKey(null, null);

public Object get(Object k1, Object k2) {
return get(setKey(k1, k2));
}

public void put(Object k1, Object k2, Object v) {
put(newKey(k1, k2), v);
}

private List newKey(Object k1, Object k2) {
return Arrays.asList(new Object[]{k1 k2});
}

private List setKey(Object k1, Object k2) {
key.set(0, k1);
key.set(1, k2);
return key;
}
}

The private key avoids constructing an ArrayList on every
get() but of course this is not thread-safe.

Am I missing an obvious flaw here, as usual?
 
G

Greg Smith

marcus said:
This is a tough one to google hehe
Is there code available, or a coupla good hints, for a fast map that
takes a pair of keys to produce a value?

I have two keys that together map to a single (non-unique) value, but
not in a particularly logical manner. This is for a personal project
and doesn't have to look pretty, so I can hard-code loading the map.
Pulling the values out, though, I don't want a hundred or so nested if
statements.

Hmm, can I set up a map of maps? the first key returns a value, which
itself is a map of possible second keys? *shudder*

i have just concatenated two strings with a separator...

String key=key1+","+key2;
hashTable.put(key, data);

greg
 

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
474,434
Messages
2,571,691
Members
48,796
Latest member
Greg L.

Latest Threads

Top