Map with two Key for a value? - java

I want to create a map that has two key :
map.put (key1,key2,value1);// Insert into map
map.get(key1,key2); // return value1
i have looking into multikeyMap but i don't know how i will do it

Sounds like you just want a key which is created from two values. You may well find that those two values should naturally be encapsulated into another type anyway - or you could create a Key2<K1, K2> type. (The naming here would allow for Key3, Key4 etc. I wouldn't encourage you to go too far though.)
For something in between, you could create a private static class within the class where this is really needed (if it's only an internal implementation detail). If it's not a natural encapsulation (e.g. it's something like "name and population", which doesn't make sense outside this specific scenario) then it would be good in terms of keeping meaningful property names, but without exposing it publicly.
In any of these scenarios, you'll end up with a new type with two final variables which are initialized in the constructor, and which contribute to both equals and hashCode. For example:
public final class Key2<K1, K2> {
private final K1 part1;
private final K2 part2;
public Key2(K1 part1, K2 part2) {
this.part1 = part1;
this.part2 = part2;
}
#Override public boolean equals(Object other) {
if (!(other instanceof Key2)) {
return false;
}
// Can't find out the type arguments, unfortunately
Key2 rawOther = (Key2) other;
// TODO: Handle nullity
return part1.equals(rawOther.part1) &&
part2.equals(rawOther.part2);
}
#Override public int hashCode() {
// TODO: Handle nullity
int hash = 23;
hash = hash * 31 + part1.hashCode();
hash = hash * 31 + part2.hashCode();
return hash;
}
// TODO: Consider overriding toString and providing accessors.
}
The more situation-specific types would be slightly simpler as they wouldn't be generic - in particular this would mean you wouldn't need to worry about the type arguments, and you could give the variables better names.

How about
class Key{
private final String key1;
private final String key2;
//accessors + hashcode + equals()
}
and
Map<Key, Value> map

You might consider using one of Guava's Table implementations. From the documentation:
A collection that associates an ordered pair of keys, called a row key
and a column key, with a single value. A table may be sparse, with
only a small fraction of row key / column key pairs possessing a
corresponding value.

If you can use outside libraries, Guava provides exactly this as Table<R, C, V>, referring to the two keys as "row" and "column" respectively. (Disclosure: I contribute to Guava.)

Why not map key a String and concatinate key1+key2

If you always want to access via key1 and key2 together you could just concatenate them with a separator together as key and use a normal map.

It's unfortunate that Java does not support tuples at language level, and therefore you have to go for ad hoc structures like the ones showed in some answers here. This leads to atrocious amount of boilerplate and code duplication.
Functional Java has a library support for tuples. The class that fits the bill here is P2. The name means "product with 2 elements". (Product is just an algebraic term for composite types.) The library supports tuples of up to 8 elements. The P{n} classes override all the necessary methods
There is a class named P that provides a static factory method p for constructing tuples.
Usage:
import fj.P2;
import fj.Ord;
import fj.data.TreeMap;
import static fj.Ord.*;
import static fj.P.*;
TreeMap<P2<Integer, String>, String> m =
TreeMap.<P2<Integer, String>, String>empty(p2Ord(intOrd, stringOrd)).
set(p(1, "2"), "onetwo").
set(p(5, "3"), "fivethree");

Related

HashMap: Is there a way to search by hashcode and not by key?

I may sound completely wrong but:
I've read as many posts as I could find here about HashMap and hashcode . I did not get what I was looking for exactly. I am going to try to be as precise as I can.
Let's say I have a huge hashmap where :
keys are of type my_struct and values as well
Now, my_struct is made of 2 Lists that can have big sizes (so one entry has a respectable size on its own).
Keys and values have a special relation : values are for sure already keys in the dictionary (something like ancenstor - descendant relation).
I was wondering whether instead of storing values of my_struct , I could store an int and then using this "int as a key" to search for the relative entry. In pseudocode I could describe it as such:
HashMap<my_struct, int> h = new HashMap<>();
......
my_struct descendant = value;
int id = a(value); // returns an id for this value
h.put(ancenstor, id);
...
// after some time I want to find the corresponding value of id
int key = h.getValue(ancestor); // == id
if(h.contains(b(key)){
...
}
So basically I am looking for :
a method : a() that turns a mystruct -->int
a method : b() that turns an int ---> my struct
Of course, both should be a 1-1 functions.
After reading Java8 documentation a() must be int hashCode() but what about b() is there something in Java?
HashMap: Is there a way to search by hashcode and not by key?
Literally ... no.
OK, so I am assuming that this is a complete and accurate description of your real problem:
So basically I am looking for :
a method : a() that maps a my_struct --> int
a method : b() that maps an int --> my_struct
Of course, both should be a 1-1 functions.
Got that.
After reading Java8 documentation a() must be int hashCode()
That is incorrect. hashCode() is not 1-1. In general, multiple objects can have the same hashCode(). Note that even identity hashcodes (as returned by Object.hashCode) are not guaranteed unique.
You could implement a my_struct.hashCode method that returns a unique integer, but the only practical way to do this would be to allocate a unique number when you create each my_struct instance, and store it in a field of the object. And that has the problem that your my_struct.equals method has to return true if and only if the my_struct instances are the same instance.
But if you can live with those limitations, then a() can indeed be my_struct.hashCode.
If you generate the numbers for the my_struct objects sequentially starting at zero, you can add all of the my_struct instances to an ArrayList<my_struct> as you create them, then you can implement b() as theList.get(int).
In code (not thread-safe!!):
public class my_struct {
private static int next = 0;
private static List<my_struct> all = new ArrayList<>();
private int ordinal;
// other fields
public my_struct(...) {
// initialize fields
this.ordinal = next++;
all.add(this);
}
public boolean equals(Object other) {
return other instanceof my_struct &&
((my_struct) other).ordinal = this.ordinal;
}
public int hashCode() {
return ordinal;
}
public static my_struct(int ordinal) {
return all.get(ordinal);
}
}
But you should also be able to see that you don't have to use the ordinal as the hashcode and implement hashCode() and equals(Object) as above. It depends on what else you are doing with these structs.
Note that this is not the same as using an IdentityHashMap.
You might take a look at IdentityHashMap which does not rely on equals and only hashes on the identify hashCode itself. This means that you can have duplicate keys that might otherwise be considered equal. So keys are only considered equal if they are the same reference.
Check out IdentityHashMap in the JavaDoc
Since you are in charge of assigning ids, you can fake the other side of the relationship by keeping my_struct objects in an array list, and using their array index as the id.
This way, mapping from my_struct to id becomes a hash lookup, while mapping from id to my_struct becomes an array list look-up.
List<my_struct> mystructs = new ArrayList<my_struct>();
... add items to mystructs
Map<my_struct,Integer> toId = new HashMap<my_struct,Integer>();
for (int i = 0 ; i != mystructs.size() ; i++) {
toId.put(mystructs.get(i), i);
}
Going from my_struct to id:
int id = toId.get(my_struct_object);
going from id to my_struct:
my_struct my_struct_object = mystructs.get(id);

Map which allows to provide the equals-comparator and the hashing function separately

While trying to model polynomials, in particular their multiplication, I run into the following problem. During the multiplication, the individual monomials of the two polynomials are multiplied and of course in can happen that I have (3x^2 y + 5x y^2) * (x + y). The result contains 3x^2 y^2 and 5 x^2 y^2, which I want to combine by addition right away.
Naturally I would like to use the part x^2 y^2 of the monomial as a key in a (hash) map to add up the different coefficients (3 and 5 in the example). But the monomial object as I envisage it should naturally also contain the coefficient, which should not be part of the map key.
Of course I could write equals/hashcode of the monomial object such that they ignore the coefficient. But this feels just so wrong, because mathematically a monomial clearly is only equal to another one if also the coefficients are equal.
Introducing a coefficient-free monomial object for intermediate operations does also not look right.
Instead of using the map, I could use a list and use a binary search with a dedicated comparator that ignores the coefficient.
Short of implementing a map which does not use the keys' equals/hashcode, but a dedicated one, are there any better ideas of how to fuse the monomials?
Since the JDK implementation of [Linked]HashMap does not permits you to override the equals/hashCode implementation, the only other ways are:
a wrapping object like this:
class A {
private final String fieldA; // equals/hashCode based on that field.
private final String fieldB; // equals/hashCode based on that field.
}
class B {
private A a;
public int hashCode() {return a.fieldA.hashCode();}
public boolean equals(Object o) {... the same ... }
}
Map<B, Value> map = new HashMap<B, Value>();
map.put(new B(new A("fieldA", "fieldB")), new Value(0));
Well, with more getters/constructors.
This can be annoying, and perhaps there exists some library (like Guava) that allows an equals/hashCode method to be given like you can give a Comparator to TreeMap.
You'll find below a sample implementation that point out what to do to decorate an existing map.
use a TreeMap with a specific Comparator. The other answer point it, but I'd say you'll need to correctly define a Comparator because this could lead to problems: if you compareTo method returns 0 when equality is reached, and 1 in other case, this means there is no natural ordering. You should try to find one, or use the wrapper object.
If you want to take the challenge, you can create a basic implementation using delegation/decoration over another HashMap (this could be another kind of map, like LinkedHashMap):
public class DelegatingHashMap<K,V> implements Map<K,V> {
private final BiPredicate<K,Object> equalsHandler;
private final IntFunction<K> hashCodeHandler;
private final Map<Wrapper<K>,V> impl = new HashMap<>();
public DelegatingHashMap(
BiPredicate<K,Object> equalsHandler,
IntFunction<K> hashCodeHandler
) {
this.equalsHandler = requireNonNull(equalsHandler, "equalsHandler");
this.hashCodeHandler= requireNonNull(hashCodeHandler, "hashCodeHandler");
}
public Object get(K key) {
Wrapper<K> wrap = new Wrapper<>(key);
return impl.get(wrap);
}
...
static class Wrapper<K2> {
private final K2 key;
private final BiPredicate<K> equalsHandler;
private final IntFunction<K> hashCodeHandler;
public int hashCode() {return hashCodeHandler.apply(key);}
public boolean equals(Object o) {
return equalsHandler.test(key, o);
}
}
}
And the code using the map:
DelegatingHashMap<String, Integer> map = new DelegatingHashMap<>(
(key, old) -> key.equalsIgnoreCase(Objects.toString(o, "")),
key -> key.toLowerCase().hashCode()
);
map.put("Foobar", 1);
map.put("foobar", 2);
System.out.println(map); // print {foobar: 2}
But perhaps the best (for the memory) would be to rewrite the HashMap to directly use the handler instead of a wrapper.
You could use a TreeMap with a custom comparator:
TreeMap(Comparator<? super K> comparator)
Constructs a new, empty tree map, ordered according to the given comparator.
(Source)
Consider using a TreeMap, which is a SortedMapand thus also a Map. You can provide a Comparator to its constructor. The sorted map will use that Comparator for sorting the map keys. But importantly, for your case, it will consuder keys to be equal if the Comparator returns 0. In your case that will require a Comparator that is not consustent with equals, which could cause you problems if you are not careful.
Another option is to introduce another class, which acts as an adaptor for a Mononomial and can be used as a map key having the properties you deserve.
I think it may be better to separate the monomial into 2 parts: the coefficient and the variable. That way you can use the variable part in your map as the key and the coefficient as the value (which can then up updated).
All this code should be implementation details inside a Polynomial object
I'm not sure why you think a coefficient-free monomial does not look right. You don't have to expose the object to the outside if you don't want. But it might be a nice way to have getters on your Polynomial to get the coefficients for each monomial.

Setting values of enumerations, and parsing string to get an enum

My enum is like this currently:
public enum Manufacturers {
Honda,
GM,
Toyota,
Ferrari
}
I need to create a Hashmap so I plan on doing this, is this correct?
Manufacturers mfg = Manufacturers.Honda;
mfg.ordinal() // save as key
i.e. I will store the key using the enumInstance.ordinal()
Also, I need to be able to parse a string which will be the ordinal value of the enumeration, and get an enum back:
Manufacturers mfg = Manufacturers.valueOf(mfgOrdinalValueAsString);
The above gave me an error (the string was "1"). Is this the correct way? I guess I should have a try/catch in there right?
The .valueOf would actually be expecting the String "GM" (for 1).
As for storing your enum values in a map, use EnumMap which is designed specifically for this - and will be fast at it, too.
If you really wanted to reference a value by its ordinal, use something like Manufacturers.values()[1].
A suggestion: better use name() to get the name of the enum as a String, and whenever you need to get back the original Enum from it, use the valueOf() method - since valueOf() expects the name, not the ordinal, as a parameter. For example:
enum Example {ONE, TWO};
String name = Example.ONE.name();
Example e = Example.valueOf(Example.class, name); // e has value ONE
If you definitely need to use the ordinal, the ordinal() method will return an index which you can use to retrieve the respective Enum from the array returned by the values() method. Like this:
int ordinal = Example.ONE.ordinal();
Example e = Example.values()[ordinal]; // e has value ONE
As has already been pointed out, consider using EnumMap, as stated in the documentation, it is
A specialized Map implementation for use with enum type keys. All of the keys in an enum map must come from a single enum type that is specified, explicitly or implicitly, when the map is created. Enum maps are represented internally as arrays. This representation is extremely compact and efficient.
EDIT
If you need to associate a different code to each element of the enum (other than its automatically assigned ordinal), you can always add it as an attribute to the enum, together with getters and setters, like this:
public enum Manufacturers {
Honda(10),
GM(20),
Toyota(30),
Ferrari(40);
private int code;
Manufacturers(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
For example:
Manufacturers m = Manufacturers.Honda;
System.out.println(m.getCode()); // prints 10
m.setCode(100);
System.out.println(m.getCode()); // prints 100
Just be aware that you won't be able to reconstruct an Enum object from the code attribute, since that was defined by the programmer.

When should I create a class for a Map key?

I'm using Java 6.
Suppose I have a class which I would like to save its instances into a map. Later on I would like to retrieve instances using only the "key fields". I'll ignore field modifiers, getters, and setters for conciseness.
class A {
String field1;
String field2;
String field3;
String field4;
//more fields
public int hashCode(){
//uses only field1 and field2
}
public boolean equals(Object o){
//uses only field1 and field2
}
}
Since Java's standard API doesn't have the MultikeyMap and I don't want to use 3rd party libraries, I have a choice of
1) creating a new class KeyA to represent the key of a map
2) use A itself as the key and populate only the "key fields" when I need to retrieve objects from a map
3) nest the maps, e.g. HashMap<String, HashMap<String, A>>
4) other workarounds
What do people normally use and when?
Given your recent edit, you should be fine to use instances of class A as keys in this situation. Lookups will be done based on the semantics of equals() and hashCode(), so this will cause instances to be retrieved by only the "key fields". Hence the following code would work as you intend:
final Map<A, String> map = new HashMap<A, Object>();
final A first = new A("fe", "fi", "fo", "fum");
map.put(first, "success");
// later on
final A second = new A ("fe", "fi", "foo", "bar");
System.out.println(map.get(second)); // prints "success";
Having said that, your description of option 2 makes me a little concerned that this might not be the most sensible option. If you create a Map<A, String>, that's a mapping from instances of class A to strings. Yet your second point implies that you want to think of it as a mapping from pairs of key fields to strings. If you're going to usually look up values based on a couple of "raw" strings, then I'd advise against this. It feels wrong (to me), to create a "fake" instance of A just to do a lookup - so in this case, you probably should create a key class that embodies the pair of strings as described in option 1. (You could even embed instances of these within your A objects to hold the key fields).
There's a similar argument for or against option 3, too. If the strings really are conceptually hierarchical, then it might well make sense. For example, if field1 was Country, and field2 was Town, one could definitely argue that the nested maps make sense - you have a mapping from country, to the map of Town->A relations within that country. But if your keys don't naturally compose in this fashion (say, if they were (x, y) coordinates), this would again not be a very natural way to represent the data, and a single-level map from XYPoint to value would be more sensible. (Likewise, if you never use the two-level map except to always go straight through both layers, one could argue the one-level map still makes more sense.)
And finally, as for option 4 -if you're always mapping to A itself, and storing the key as its own value (e.g. if you want to canonicalise your A instances, a bit like String.intern()) then as was pointed out you needn't use a Map at all, and a Set will do the job here. The Map is useful when you want to establish relationships between different objects, whereas a Set automatically gives you the uniqueness of objects without any extra conceptual overhead.
If you do use the class itself as a key, be warned though that objects should only generally be used as keys if their hashCode (and the behaviour of equals) won't change over time. Typically this means the keys are immutable, though here you could afford to have mutable "non-key" fields. If you were to break this rule, you'd see odd behaviour such as the following:
// Populate a map, with an A as the key
final Map<A, String> map = new HashMap<A, Object>();
final A a = new A("one", "two", "three", "four");
map.put(a, "here");
// Mutate a
a.setField1("un");
// Now look up what we associated with it
System.out.println(map.get(a)); // prints "null" - huh?
System.out.println(map.containsKey(a)); // prints "false"
I'd create an Index class, something like this (warning: untested code), to abstract out the indexing functionality. Why Java doesn't have something like this already is puzzling to me.
interface Indexer<T, K>
{
/** extract key from index */
public K getIndexKey(T object);
}
class Index<T,K>
{
final private HashMap<K,List<T>> indexMap = new HashMap<K,List<T>>();
final private Indexer<T,K> indexer;
public Index(Indexer<T,K> indexer)
{
this.indexer = indexer;
}
public void add(T object) {
K key = this.indexer.getIndexKey(object);
List<T> values = this.indexMap.get(key);
if (values == null)
{
values = new ArrayList<T>();
this.indexMap.put(key, values);
}
values.add(object);
}
public void remove(T object) {
K key = this.indexer.getIndexKey(object);
List<T> values = this.indexMap.get(key);
if (values != null)
{
values.remove(object);
}
}
public List<T> lookup(K key) {
List<T> values = this.indexMap.get(key);
return values == null
? Collections.emptyList()
: Collections.unmodifiableList(values);
}
}
example relevant to your class A:
Index<A,String> index1 = new Index<A,String>(new Indexer<A,String>() {
#Override public String getIndexKey(A object)
{
return object.field1;
}
});
Index<A,String> index2 = new Index<A,String>(new Indexer<A,String>() {
#Override public String getIndexKey(A object)
{
return object.field2;
}
});
/* repeat for all desired fields */
You would manually have to add and remove entries from the indices, but all the grungework below those operations is handled by the Index class.
Your class has "key fields". I would suggest to create a parent class, ParentA, with those key fields (which certainly map to a concept in your domain) and inherit this class in your child class A.
Override hashCode() and equals() in the ParentA class.
Use a Map<ParentA, A> to store your A instances and give the instance as key and value.
To retrieve a specific A instance, create a new ParentA instance, pA, with your key fields set, and do
A a = map.get(pA);
That's it.
Another way is to create a AIdentifier class with key fields and add an instance as A property id. So you add your instance with map.put(a.id, a); That's inheritance vs composition pattern discussion :)

Caching objects built with multiple parameters

I have a factory that creates objects of class MyClass, returning already generated ones when they exist. As I have the creation method (getOrCreateMyClass) taking multiple parameters, which is the best way to use a Map to store and retrieve the objects?
My current solution is the following, but it doesn't sound too clear to me.
I use the hashCode method (slightly modified) of class MyClass to build an int based on the parameters of class MyClass, and I use it as the key of the Map.
import java.util.HashMap;
import java.util.Map;
public class MyClassFactory {
static Map<Integer, MyClass> cache = new HashMap<Integer, MyClass>();
private static class MyClass {
private String s;
private int i;
public MyClass(String s, int i) {
}
public static int getHashCode(String s, int i) {
final int prime = 31;
int result = 1;
result = prime * result + i;
result = prime * result + ((s == null) ? 0 : s.hashCode());
return result;
}
#Override
public int hashCode() {
return getHashCode(this.s, this.i);
}
}
public static MyClass getOrCreateMyClass(String s, int i) {
int hashCode = MyClass.getHashCode(s, i);
MyClass a = cache.get(hashCode);
if (a == null) {
a = new MyClass(s, i);
cache.put(hashCode , a);
}
return a;
}
}
Your getOrCreateMyClass doesn't seem to add to the cache if it creates.
I think this will also not perform correctly when hashcodes collide. Identical hashcodes do not imply equal objects. This could be the source of the bug you mentioned in a comment.
You might consider creating a generic Pair class with actual equals and hashCode methods and using Pair<String, Integer> class as the map key for your cache.
Edit:
The issue of extra memory consumption by storing both a Pair<String, Integer> key and a MyClass value might be best dealt with by making the Pair<String, Integer> into a field of MyClass and thereby having only one reference to this object.
With all of this though, you might have to worry about threading issues that don't seem to be addressed yet, and which could be another source of bugs.
And whether it is actually a good idea at all depends on whether the creation of MyClass is much more expensive than the creation of the map key.
Another Edit:
ColinD's answer is also reasonable (and I've upvoted it), as long as the construction of MyClass is not expensive.
Another approach that might be worth consideration is to use a nested map Map<String, Map<Integer, MyClass>>, which would require a two-stage lookup and complicate the cache updating a bit.
You really shouldn't be using the hashcode as the key in your map. A class's hashcode is not intended to necessarily guarantee that it will not be the same for any two non-equal instances of that class. Indeed, your hashcode method could definitely produce the same hashcode for two non-equal instances. You do need to implement equals on MyClass to check that two instances of MyClass are equal based on the equality of the String and int they contain. I'd also recommend making the s and i fields final to provide a stronger guarantee of the immutability of each MyClass instance if you're going to be using it this way.
Beyond that, I think what you actually want here is an interner.... that is, something to guarantee that you'll only ever store at most 1 instance of a given MyClass in memory at a time. The correct solution to this is a Map<MyClass, MyClass>... more specifically a ConcurrentMap<MyClass, MyClass> if there's any chance of getOrCreateMyClass being called from multiple threads. Now, you do need to create a new instance of MyClass in order to check the cache when using this approach, but that's inevitable really... and it's not a big deal because MyClass is easy to create.
Guava has something that does all the work for you here: its Interner interface and corresponding Interners factory/utility class. Here's how you might use it to implement getOrCreateMyClass:
private static final Interner<MyClass> interner = Interners.newStrongInterner();
public static MyClass getOrCreateMyClass(String s, int i) {
return interner.intern(new MyClass(s, i));
}
Note that using a strong interner will, like your example code, keep each MyClass it holds in memory as long as the interner is in memory, regardless of whether anything else in the program has a reference to a given instance. If you use newWeakInterner instead, when there isn't anything elsewhere in your program using a given MyClass instance, that instance will be eligible for garbage collection, helping you not waste memory with instances you don't need around.
If you choose to do this yourself, you'll want to use a ConcurrentMap cache and use putIfAbsent. You can take a look at the implementation of Guava's strong interner for reference I imagine... the weak reference approach is much more complicated though.

Categories

Resources