Tuesday, May 7, 2013

Case Insensitive Map

I use Maps often, especially using a String as the key. Working with database fields, there are times when I wished that String was case insensitive. So I used a couple of LinkedHashMap objects to implement my own...

Usage:

Map<String, Object> myMap = new CaseInsensitiveLinkedHashMap<Object>()
Object o1 = new Object();
myMap.put("id7", o1);
Object o2 = myMap.get("ID7");
System.out.println(o1==o2 ? "success" : "failure"); // prints "success"

// end

It preserves the original capitalization of the keys while maintaining the efficiency of the hash lookups, but the lookups are case insensitive.

Source:
        

package util;

import java.util.*;

/**
 * allows you to create a Map<String, ?> where the String key is case insensitive.
 * @author Jonathan
 */
public final class CaseInsensitiveLinkedHashMap<T> implements Map<String, T> {

    private final Map<String, String> keys;
    private final Map<String, T> values;

    public CaseInsensitiveLinkedHashMap() {
        keys = new LinkedHashMap<String, String>();
        values = new LinkedHashMap<String, T>();
    }

    public CaseInsensitiveLinkedHashMap(int initialCapacity) {
        keys = new LinkedHashMap<String, String>(initialCapacity);
        values = new LinkedHashMap<String, T>(initialCapacity);
    }

    public CaseInsensitiveLinkedHashMap(int initialCapacity, float loadFactor) {
        keys = new LinkedHashMap<String, String>(initialCapacity, loadFactor);
        values = new LinkedHashMap<String, T>(initialCapacity, loadFactor);
    }

    public CaseInsensitiveLinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
        keys = new LinkedHashMap<String, String>(initialCapacity, loadFactor, accessOrder);
        values = new LinkedHashMap<String, T>(initialCapacity, loadFactor, accessOrder);
    }

    public CaseInsensitiveLinkedHashMap(Map<? extends String, ? extends T> initialValues) {
        this(initialValues.size());
        for (Entry<? extends String, ? extends T> entry : initialValues.entrySet()) {
            put(entry.getKey(), entry.getValue());
        }
    }

    @Override
    public boolean containsKey(Object key) {
        return containsKey(key.toString());
    }

    public boolean containsKey(String key) {
        return values.containsKey(key.toLowerCase());
    }

    @Override
    public T get(Object key) {
        return get(key.toString());
    }

    public T get(String key) {
        return values.get(key.toLowerCase());
    }

    @Override
    public T put(String key, T value) {
        final String lowerCaseKey = key.toLowerCase();
        keys.put(lowerCaseKey, key);
        return values.put(lowerCaseKey, value);
    }

    @Override
    public T remove(Object key) {
        return remove(key.toString());
    }

    public T remove(String key) {
        final String lowerCaseKey = key.toLowerCase();
        keys.remove(lowerCaseKey);
        return values.remove(lowerCaseKey);
    }

    @Override
    public void putAll(Map<? extends String, ? extends T> m) {
        for (Entry<? extends String, ? extends T> entry : m.entrySet()) {
            put(entry.getKey(), entry.getValue());
        }
    }

    @Override
    public void clear() {
        keys.clear();
        values.clear();
    }

    @Override
    public Set<String> keySet() {
        return new LinkedHashSet<String>(keys.values());
    }

    @Override
    public Collection<T> values() {
        return values.values();
    }

    @Override
    public Set<Entry<String, T>> entrySet() {
        Set<Entry<String, T>> set = new LinkedHashSet<Entry<String, T>>();
        for (final String keyLowerCase : keys.keySet()) {
            Entry<String, T> entry = new Entry<String, T>() {

                final String key = keys.get(keyLowerCase);

                @Override
                public String getKey() {
                    return key;
                }

                @Override
                public T getValue() {
                    if (containsKey(key)) {
                        return get(key);
                    }
                    return null;
                }

                @Override
                public T setValue(T value) {
                    return put(key, value);
                }

            };
            set.add(entry);
        }
        return set;
    }

    @Override
    public int size() {
        return values.size();
    }

    @Override
    public boolean isEmpty() {
        return values.isEmpty();
    }

    @Override
    public boolean containsValue(Object value) {
        return values.containsValue(value);
    }

}

// end