5.11. Retrieving a Key by a Value

Problem

You need a Map that allows you to access a value by a key and a key by a value.

Solution

BidiMap in Commons Collections provides an implementation of Map, which can be reversed if both the keys and values are unique; you can use a BidiMap to retrieve a value for a key or a key for a value. The following example demonstrates the use of a BidiMap to access state names by state abbreviation and state abbreviations by state names:

BidiMap bidiMap = new DualHashBidiMap( );

bidiMap.put( "il", "Illinois" );
bidiMap.put( "az", "Arizona" );
bidiMap.put( "va", "Virginia" );

// Retrieve the key with a value via the inverse map
String vaAbbreviation = bidiMap.inverseBidiMap( ).get( "Virginia" );
 
// Retrieve the value from the key
String illinoisName = bidiMap.get( "il" );

DualHashBidiMap stores keys and values in two HashMap instances. One HashMap stores keys as keys and values as values, and the other HashMap stores the inverse—values as keys and keys as values.

Discussion

In Example 5-11, a BidiMap is used to store country names and country codes; an application stores ISO country codes and translates between ISO country codes and country names to present intelligible output—“us” is translated to “United States.” Alternatively, when a user types in a name of a country, the application needs to be able to produce the country code for that country name—“United States” must be translated back to “us.”

Example 5-11. Storing ISO country codes in a BidiMap

package com.discursive.jccook.collections.bidi;

import org.apache.commons.collections.BidiMap;
import org.apache.commons.collections.bidimap.DualHashBidiMap;

public class BidiMapExample {

    private BidiMap countryCodes = new DualHashBidiMap( );

    public static void main(String[] args) {
        BidiMapExample example = new BidiMapExample( );
        example.start( );
    }
    
    private void start( ) {
        populateCountryCodes( );
        
        String countryName = (String) countryCodes.get( "tr" );
        System.out.println( "Country Name for code 'tr': " + countryName );

        String countryCode = 
            (String) countryCodes.inverseBidiMap( ).get("Uruguay");
        System.out.println( "Country Code for name 'Uruguay': " + countryCode );
            
        countryCode = (String) countryCodes.getKey("Ukraine");
        System.out.println( "Country Code for name 'Ukraine': " + countryCode );
    }
    
    private void populateCountryCodes( ) {
        countryCodes.put("to","Tonga");
        countryCodes.put("tr","Turkey");
        countryCodes.put("tv","Tuvalu");
        countryCodes.put("tz","Tanzania");
        countryCodes.put("ua","Ukraine");
        countryCodes.put("ug","Uganda");
        countryCodes.put("uk","United Kingdom");
        countryCodes.put("um","USA Minor Outlying Islands");
        countryCodes.put("us","United States");
        countryCodes.put("uy","Uruguay");
    }
}

The previous example makes sense because country codes and country names are both unique; there is only one entry for “Djibouti,” “dj,"and no other country has an overlapping code because country codes are defined by an International Organization for Standardization (ISO) standard, ISO 3166. If you attempt to insert a duplicate key in a regular map, the existing entry with the same key would be replaced by the new value. In a BidiMap, if you insert a duplicate value, or a duplicate key, the entry holding this value is replaced by a new entry. The following example illustrates this concept:

private BidiMap bidiMap = new DualHashBidiMap( );

// Insert initial content { "one:"red", "two":"green", "three":"blue" }
bidiMap.put("one","red");
bidiMap.put("two","green");
bidiMap.put("three","blue");

// replace "one" key entry
bidiMap.put("one","black");

// replace "green" value entry
bidiMap.put("five","green");

// Contents are now { "one":"black", "three":"blue", "five":"green" }

Changing key “one,” value “black” replaces the original key “one,” value “red” because the key is duplicated; this behavior is consistent with a normal implementation of Map. The difference in a BidiMap is that when adding key “five,” value “green” to a BidiMap, the previous key “two,” value “green” is replaced with a new entry because “green” is a duplicate value. A regular Map simply adds another entry, and getting the value of either the “five,” or “two,” key would return the value “green.” Because “green” already occurs as a key in the inverse map, the entry corresponding to the “two,” key is removed and replaced by a new entry. Bidirectional access to keys by value is only possible if keys and values form two unique sets.

There are three implementations of the BidiMap interface: DualHashBidiMap, DialTreeBidiMap, and TreeBidiMap. A DualHashBidiMap is the simplest option, storing keys and values in two separate instances of HashMap. When a value is requested by key, one HashMap is consulted, and when a key is requested by value, the inverse HashMap is consulted. The DualHashMap is likely to be your implementation of choice if it is not important to keep track of the insertion order; it has a straightforward implementation using the familiar HashMap.

If you need to preserve the order of insertion, a DualTreeBidiMap uses two separate TreeMap instances to hold the regular and inverse mappings. This implementation implements the SortedMap interface that keeps track of the order of insertion and provides subMap( ), headMap( ), and tailMap( ) methods. A third implementation, TreeBidiMap, implements BidiMap without maintaining two internal storage maps. Instead, TreeBidiMap stores nodes in a red-black tree, identifying each node as both a key and a value; it costs twice as much to put( ) into a TreeBidiMap, but this implementation comes in handy if you are worried about memory consumption—it does not need to store each key and value twice in two maps.

See Also

This example used ISO 3166 country codes, a list of every country and corresponding two letter country code. If you are writing an application for a worldwide audience, you may find the following list helpful: http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.244.217