Tuesday, November 8, 2011

Bi-Directional Maps



Playing with Bi-directional maps
Problem Statement
You need to access county via country code and vice versa like
USà United States
United Statesà US

Approach :1

You will create two maps

Map cityCodeMap
Map< cityName, cityCode > cityNameMap
This is definitely not a preferred way.

Approach :2 
We need something like a bidirectional map (We can again give thanks to Apache Foundation)
BidiMap in Apache 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 aBidiMap 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" );
 // Output is va

// Retrieve the value from the key
String illinoisName = bidiMap.get( "il"
 // Output is Illinois

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.
Bi-Directional-Map


Discussion

Very often in an application we may need to store country names and country codes and use them back n forth. Like

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");
    }
}

You can guess the output by now it’s pretty simple:

Country Name for code 'tr': Turkey
Country Code for name 'Uruguay': uy
Country Code for name 'Ukraine': ua




The previous example makes sense because country codes and country names are both unique; 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( );
bidiMap.put("one","red");
bidiMap.put("two","green");
bidiMap.put("three","blue");

System.out.println(bidiMap);
// Output is { "one":"red", "two":"green", "three":"blue" }

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

System.out.println(bidiMap);
// Output is { "one":"black", "three":"blue", "five":"green" }

Here we need to observe two very important things
    1)      Inserting a duplicate key, overwrites the original value (Normal implementation of Map)
    2)      Inserting a duplicate value, overwrites its original key (A regular Map simply adds another entry)

1 comment:

  1. Here the important thing to notice is the last two point.....Even If you inset a duplicate value it over writes its corresponding key

    ReplyDelete