A map is a very powerful data structure that lets us relate one thing to another in pairs. One of these things is a “key,” and the other is a “value,” so we call the pairs “key-value” pairs. For now, know that one of the benefits of maps is that they have very efficient lookup. Whereas arrays or lists might require a linear search, there is some magic going on (which we will eventually cover) that allows maps to find whatever you are looking for almost instantaneously, both in the human-time sense and the computer-time sense.
As I’m sure you’ve gathered by now, I’m a huge fan of
putting links to official Java documentation in these articles. Look at it here.
If you open the documentation link, you’ll immediately see how HashMaps are
created: with the declaration of two types in the angle brackets, just as we
had one type in angle brackets for Lists, Queues, and Stacks. Recall that,
since we need both a key and a value, we need the two types this time, not just
one.
Look at this example code snippet:
import java.util.HashMap;
public class HashMapExample {
public static void
main(String[] args) {
// Create a
HashMap
HashMap<String, Integer> map = new HashMap<>(); // notice the pair of types
// Add
key-value pairs
map.put("Apple", 3);
map.put("Banana", 5);
map.put("Orange", 2);
// Access a
value by key
System.out.println("Quantity of Apples: " +
map.get("Apple"));
// Check if a
key exists
if
(map.containsKey("Banana")) {
System.out.println("Banana is in the map.");
}
// Remove a
key-value pair
map.remove("Orange");
// Iterate
through the HashMap
for
(String key : map.keySet()) {
System.out.println(key + ":
" + map.get(key));
}
}
First, notice the import statement and how we declare the HashMap.
(The declaration is legal because
every HashMap is a Map.) Second, take note of the names of the operations:
the “add” operation is called “put,” and the “retrieve” operation is called “get.”
To check if a particular key exists, there is a containsKey() method; for
values, there is a similar containsValue(). Removing a pair—not just a key, or
not just a value—is done by remove(), passing in the key. get() takes in a key
and returns the associated value.
In this case, the mapping is one-directional: “Delta 105” maps to “Atlanta to
Guarulhos.” Naturally, “Atlanta to Guarulhos” should map to “Delta 105,” since
it does in the real world: the delta flight from ATL to GRU is 105; and Delta
105 is the flight from ATL to GRU. These kinds of maps do exist, but the
HashMap is not one by default. To get bidirectional mapping, either make two HashMaps
with opposite keys and values (the key of one is the value of the other) or use
a BiMap. Google has an implementation in their Guava library, but,
whenever I’ve wanted to do something bidirectional, I have always found it
easier to write (and to understand later) the code that just uses two opposite maps
the regular way.
This is how bidirectional mapping would look:
import java.util.HashMap;
import java.util.Map;
public class SimpleBiMap<K, V> {
private final
Map<K, V> forwardMap = new HashMap<>();
private final
Map<V, K> reverseMap = new HashMap<>();
public void put(K
key, V value) {
if
(forwardMap.containsKey(key) || reverseMap.containsKey(value)) {
throw new
IllegalArgumentException("Key or value already exists in the bimap");
}
forwardMap.put(key, value);
reverseMap.put(value, key);
}
public V
getValue(K key) {
return
forwardMap.get(key);
}
public K getKey(V
value) {
return
reverseMap.get(value);
}
public void
removeByKey(K key) {
V value =
forwardMap.remove(key);
if (value !=
null) {
reverseMap.remove(value);
}
}
public void
removeByValue(V value) {
K key =
reverseMap.remove(value);
if (key !=
null) {
forwardMap.remove(key);
}
}
}
public class AirlineRouteMap {
public static void
main(String[] args) {
SimpleBiMap<String, String> routeMap = new SimpleBiMap<>();
// Assign
routes
routeMap.put("Delta 105", "Atlanta to Sao Paulo");
routeMap.put("United 222", "New York to London");
routeMap.put("American 333", "Los Angeles to
Tokyo");
// Look up by
flight code
System.out.println("Route for Delta 105: " +
routeMap.getValue("Delta 105"));
// Output:
Route for Delta 105: Atlanta to Sao Paulo
// Look up by
route description
System.out.println("Flight code for 'New York to London': " +
routeMap.getKey("New York to London"));
// Output:
Flight code for 'New York to London': United 222
}
}
Here, SimpleBiMap maintains the two opposite maps. AirlineRouteMap simply
implements a specific case for airline routes: given a city pair, you get the
number, and given the number, you get the city pair.
Keys must be unique in a HashMap; values need not be.
Because of this, if you want to get all the keys, the data structure that is returned
is a Set, and the data structure of all the values is a Collection. If what you
want is a Set of key-value pairs, that can come out of a HashMap as the
entrySet. Map has inside of itself the class Map.Entry<K,V>, so should
you want a Set of key-value pairs rather than a Map, you can get it.
No comments:
Post a Comment