How to create a HashMap with two keys (Key-Pair, Value)?
There are several options:
2 dimensions
Map of maps
Map<Integer, Map<Integer, V>> map = //...
//...
map.get(2).get(5);
Wrapper key object
public class Key {
private final int x;
private final int y;
public Key(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Key)) return false;
Key key = (Key) o;
return x == key.x && y == key.y;
}
@Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
}
Implementing equals()
and hashCode()
is crucial here. Then you simply use:
Map<Key, V> map = //...
and:
map.get(new Key(2, 5));
Table
from Guava
Table<Integer, Integer, V> table = HashBasedTable.create();
//...
table.get(2, 5);
Table
uses map of maps underneath.
N dimensions
Notice that special Key
class is the only approach that scales to n-dimensions. You might also consider:
Map<List<Integer>, V> map = //...
but that's terrible from performance perspective, as well as readability and correctness (no easy way to enforce list size).
Maybe take a look at Scala where you have tuples and case
classes (replacing whole Key
class with one-liner).
How to write/put to a HashMap with two keys (Key-Pair, Value)?
If you're using Java 8+, you can do (if your V
type parameter is a string):
map.computeIfAbsent(2, e -> new HashMap<>()).put(5, "value");
HashMap with multiple values under the same key
You could:
- Use a map that has a list as the value.
Map<KeyType, List<ValueType>>
. - Create a new wrapper class and place instances of this wrapper in the map.
Map<KeyType, WrapperType>
. - Use a tuple like class (saves creating lots of wrappers).
Map<KeyType, Tuple<Value1Type, Value2Type>>
. - Use mulitple maps side-by-side.
Examples
1. Map with list as the value
// create our map
Map<String, List<Person>> peopleByForename = new HashMap<>();
// populate it
List<Person> people = new ArrayList<>();
people.add(new Person("Bob Smith"));
people.add(new Person("Bob Jones"));
peopleByForename.put("Bob", people);
// read from it
List<Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs[0];
Person bob2 = bobs[1];
The disadvantage with this approach is that the list is not bound to exactly two values.
2. Using wrapper class
// define our wrapper
class Wrapper {
public Wrapper(Person person1, Person person2) {
this.person1 = person1;
this.person2 = person2;
}
public Person getPerson1() { return this.person1; }
public Person getPerson2() { return this.person2; }
private Person person1;
private Person person2;
}
// create our map
Map<String, Wrapper> peopleByForename = new HashMap<>();
// populate it
peopleByForename.put("Bob", new Wrapper(new Person("Bob Smith"),
new Person("Bob Jones"));
// read from it
Wrapper bobs = peopleByForename.get("Bob");
Person bob1 = bobs.getPerson1();
Person bob2 = bobs.getPerson2();
The disadvantage to this approach is that you have to write a lot of boiler-plate code for all of these very simple container classes.
3. Using a tuple
// you'll have to write or download a Tuple class in Java, (.NET ships with one)
// create our map
Map<String, Tuple2<Person, Person> peopleByForename = new HashMap<>();
// populate it
peopleByForename.put("Bob", new Tuple2(new Person("Bob Smith",
new Person("Bob Jones"));
// read from it
Tuple<Person, Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs.Item1;
Person bob2 = bobs.Item2;
This is the best solution in my opinion.
4. Multiple maps
// create our maps
Map<String, Person> firstPersonByForename = new HashMap<>();
Map<String, Person> secondPersonByForename = new HashMap<>();
// populate them
firstPersonByForename.put("Bob", new Person("Bob Smith"));
secondPersonByForename.put("Bob", new Person("Bob Jones"));
// read from them
Person bob1 = firstPersonByForename["Bob"];
Person bob2 = secondPersonByForename["Bob"];
The disadvantage of this solution is that it's not obvious that the two maps are related, a programmatic error could see the two maps get out of sync.
How link multiple keys to the same value in the HashMap
If you want to associate a group of keys with the same object, it can be achieved by using a mutable object as a value.
For instance, you can make use of StringBuilder
or implement a custom class. It'll be more performant and easier than an approach with implementing your own map which extends HashMap
and is able to track these groups of keys and triggers a series of updates for each call of put()
, replace()
or remove()
.
Solution with a custom mutable Container
can look like this:
HashMap<String, Container<Integer>> map = new HashMap<>();
Container<Integer> commonValue = new Container<>(0);
map.put("x", commonValue);
map.put("y", commonValue);
System.out.println("Value for 'x': " + map.get("x"));
System.out.println("Value for 'y': " + map.get("y"));
commonValue.setValue(10);
System.out.println("Value for 'x': " + map.get("x"));
System.out.println("Value for 'y': " + map.get("y"));
The Container
class itself.
public class Container<T> {
private T value;
public Container(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
As I have already said, the alternative is to use a mutable class that is already provided by the JDK. The code is then almost the same:
HashMap<String, StringBuilder> map = new HashMap<>();
StringBuilder commonValue = new StringBuilder("0");
map.put("x", commonValue);
map.put("y", commonValue);
System.out.println("Value for 'x': " + map.get("x"));
System.out.println("Value for 'y': " + map.get("y"));
commonValue.replace(0, commonValue.length(), "10");
System.out.println("Value for 'x': " + map.get("x"));
System.out.println("Value for 'y': " + map.get("y"));
Output (by both versions)
Value for 'x': 0
Value for 'y': 0
Value for 'x': 10
Value for 'y': 10
How to map Key Value pair from one map onto another
Apparently you want a third map made of keys from the second map, and matching values from the first map.
Map< String , String > thirdMap = new HashMap<>() ;
for ( Map.Entry< String , String > entry : secondMap.entrySet() ) {
thirdMap.put(
entry.getKey() , // Second map’s key.
firstMap.get( entry.getValue() ) // First map’s value.
);
}
How to implement a Map with multiple keys?
Two maps. One Map<K1, V>
and one Map<K2, V>
. If you must have a single interface, write a wrapper class that implements said methods.
Related Topics
Jaxb Marshalling Unmarshalling with Cdata
Facebook Offline Access Step-By-Step
Java - Delete Line from Text File by Overwriting While Reading It
How to Update an Entity Using Spring-Data-Jpa
Modifying Local Variable from Inside Lambda
Get a Node's Inner Xml as String in Java Dom
How to Format Localdate to String
Eclipse Optimize Imports to Include Static Imports
How to Write Our Own Iterator in Java
Use of Java [Interfaces/Abstract Classes]
Difference Between One-To-Many, Many-To-One and Many-To-Many
How Does the Spring @Responsebody Annotation Work
How to Set Java_Home in MAC Permanently
Performance Concurrenthashmap VS Hashmap
Spark Strutured Streaming Automatically Converts Timestamp to Local Time