Структура данных пар, где каждое значение (в паре) отображается на другое значение? - PullRequest
5 голосов
/ 27 марта 2012

Я снова вернулся с похожим вопросом. Есть ли DataType, который может вернуть своего конкретного партнера? Например:

ExampleType<String,String> test = new ExampleType<String,String>();
test.put("hello","hi");

Если бы я набрал test.get ("привет"), он бы возвратил "привет", а если бы я набрал test.get ("привет"), он бы возвратил "привет".

Моим единственным предположением для этого может быть двухмерный массив, но я не уверен, как бы это реализовать. На данный момент, единственный способ понять, как это сделать - это создать две разные хэш-карты и поменять местами ключи в каждой. (очевидно, это не очень эффективно / эффективно).

Спасибо за помощь!

Ответы [ 4 ]

10 голосов
/ 27 марта 2012

Для этого вы можете использовать BiavaMap Guava . Он также поддерживает обратный поиск:

Двунаправленная карта (или «двунаправленная карта») - это карта, которая сохраняет уникальность своих значений, а также ключей. Это ограничение позволяет бимапам поддерживать «инверсное представление», которое является еще одним бимапом, содержащим те же записи, что и этот бимап, но с обращенными ключами и значениями.

Если у вас уже есть зависимость от commons-collection, вы также можете использовать BidiMap.

3 голосов
/ 27 марта 2012

Ничего не встроено, поэтому вы либо используете сторонний пакет, например BiMap от Guava, упомянутый Pangea, либо, если вы хотите свернуть свой собственный, если вам нужны два разных типа данных, идея с 2-мя картами неплоха, есливаши ключи и значения имеют тот же тип, что вы можете использовать одну карту с двойными записями:

public class BiMap<T>{

    private Map<T,T> theMap = new HashMap<T,T>();

    public void put( T key, T value ){ put( key, value, false ); }
    public void forcePut( T key, T value ){ put( key, value, true ); }

    private void put( T key, T value, boolean force ){
        if( force || !theMap.containsKey(value) ){
            theMap.remove( theMap.remove( key ) );
            theMap.put( key, value );
            theMap.put( value, key );
        }else if( !theMap.get( value ).equals( key ) ){
            // If you allow null values&keys this will get more complicated.

            throw new IllegalArgumentException();
            // can make this more informative.
        }
        // else the pair is already in, there's nothing to do.
    }

    public T get( T key ){ return theMap.get( key ); }

    public T remove( T key ){
        T value = theMap.remove( key );
        if( value != null ) theMap.remove( value );
        return value;
    }
}

Обратите внимание, что, поскольку все является объектом, с точки зрения эффективности / пространства не так много отходов:единственное, что вы храните дважды, это адреса объектов.То же самое относится и к вашей идее с двумя картами.

Кроме того, не составит труда добавить необходимые методы, чтобы реализовать интерфейс Map<T,T> для обеспечения соответствия.

0 голосов
/ 27 марта 2012

Предполагая, что вы не собираетесь различать, какую часть пары вы запрашиваете (то есть вы хотите видеть

test.get("hi") => "hello"
test.get("hello") => "hi"

, почему бы просто не вставить оба ключа в одну карту?

test.put("hello","hi");
test.put("hi","hello");
0 голосов
/ 27 марта 2012

Два ArrayLists, вероятно, будет самым простым. Просто убедитесь, что вы храните пары в одном индексе, и он должен работать нормально. Код будет выглядеть примерно так:

ArrayList<String> list1 = new ArrayList<String>();
ArrayList<String> list2 = new ArrayList<String>();
list1.add("hi");
list2.add("hello");
get("hi");

и ваш метод get:

get(String s){
    return list2.get( list1.indexOf(s) );
}

Не знаю, является ли это лучшим решением, но это решение.

...