Подтвердить что ты не робот

Двунаправленная многозначная карта в Java

Я ищу способ хранения пар ключ-значение. Мне нужно, чтобы поиск был двунаправленным, но в то же время мне нужно сохранить несколько значений для одного и того же ключа. Другими словами, что-то вроде BidiMap, но для каждого ключа может быть несколько значений. Например, он должен иметь возможность удерживать пары, такие как: "s1" → 1, "s2" → 1, "s3" → 2, и мне нужно получить значение, сопоставленное каждому ключу, и для каждого значения, получите все связанные с ним ключи.

4b9b3361

Ответ 1

Итак, вам нужна поддержка отношений "многие ко многим"? Ближе всего вы можете получить Guava Multimap как @Mechkov написал, но более конкретно Multimap комбинация с Multimaps.invertFrom. "BiMultimap" еще не реализован, но есть проблема, запрашивающая эту функцию в библиотеке Google Guava.

На этом этапе у вас есть несколько вариантов:

  • Если ваш "BiMultimap" будет неизменным, используйте Multimaps.invertFrom и ImmutableMultimap/ImmutableListMultimap/ImmutableSetMultimap (каждый из этих трех имеет разные значения хранения коллекции). Некоторый код (пример, взятый из приложения I, использует Enum и Sets.immutableEnumSet):

    public class RolesAndServicesMapping {
        private static final ImmutableMultimap<Service, Authority> SERVICES_TO_ROLES_MAPPING = 
             ImmutableMultimap.<Service, Authority>builder()
                .put(Service.SFP1, Authority.ROLE_PREMIUM)
                .put(Service.SFP, Authority.ROLE_PREMIUM)
                .put(Service.SFE, Authority.ROLE_EXTRA)
                .put(Service.SF, Authority.ROLE_STANDARD)
                .put(Service.SK, Authority.ROLE_STANDARD)
                .put(Service.SFP1, Authority.ROLE_ADMIN)
                .put(Service.ADMIN, Authority.ROLE_ADMIN)
                .put(Service.NONE, Authority.ROLE_DENY)
                .build();
    
        // Whole magic is here:
        private static final ImmutableMultimap<Authority, Service> ROLES_TO_SERVICES_MAPPING =
                SERVICES_TO_ROLES_MAPPING.inverse();
        // before guava-11.0 it was: ImmutableMultimap.copyOf(Multimaps.invertFrom(SERVICES_TO_ROLES_MAPPING, HashMultimap.<Authority, Service>create()));
    
        public static ImmutableSet<Authority> getRoles(final Service service) {
            return Sets.immutableEnumSet(SERVICES_TO_ROLES_MAPPING.get(service));
        }
    
        public static ImmutableSet<Service> getServices(final Authority role) {
            return Sets.immutableEnumSet(ROLES_TO_SERVICES_MAPPING.get(role));
        }
    }
    
  • Если вы действительно хотите, чтобы ваш Multimap был модифицируемым, будет сложно поддерживать варианты K- > V и V- > K, если вы не будете изменять только kToVMultimap и вызывать invertFrom каждый раз, когда вы хотите иметь свою инвертированную копию (и сделать эту копию немодифицируемой, чтобы убедиться, что вы случайно не изменяете vToKMultimap, что не будет обновлять kToVMultimap). Это не оптимально, но в этом случае должно быть сделано.

  • (Не ваш случай, возможно, упоминается как бонус): BiMap интерфейс и классы реализации имеет метод .inverse(), который дает BiMap<V, K> вид из BiMap<K, V> и сам после biMap.inverse().inverse(). Если эта проблема, о которой я упоминал ранее, она, вероятно, будет иметь нечто похожее.

  • (EDIT Октябрь 2016) Вы также можете использовать новый графический API, который будет присутствовать в Guava 20:

    В целом, common.graph поддерживает графики следующих разновидностей:

    • ориентированные графики
    • неориентированные графики
    • узлы и/или ребра со связанными значениями (веса, метки и т.д.)
    • которые выполняют/не разрешают автопилы
    • которые делают/не позволяют параллельные ребра (графики с параллельными ребрами иногда называют мультиграфами)
    • чьи узлы/ребра упорядочиваются, сортируются или неупорядочены

Ответ 2

Что случилось с наличием двух карт, ключей- > значений, значений- > ключей?

Ответ 4

Используя Google Guava, мы можем написать примитивную BiMulitMap, как показано ниже.

import java.util.Collection;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

public class BiMultiMap<K,V> {

    Multimap<K, V> keyToValue = ArrayListMultimap.create();
    Multimap<V, K> valueToKey = ArrayListMultimap.create();

    public void putForce(K key, V value) {
        keyToValue.put(key, value);
        valueToKey.put(value, key);
    }

    public void put(K key, V value) {
        Collection<V> oldValue = keyToValue.get(key);
        if ( oldValue.contains(value) == false ) {
            keyToValue.put(key, value);
            valueToKey.put(value, key);
        }
    }

    public Collection<V> getValue(K key) {
        return keyToValue.get(key);
    }

    public Collection<K> getKey(V value) {
        return valueToKey.get(value);
    }

    @Override
    public String toString() {
        return "BiMultiMap [keyToValue=" + keyToValue + ", valueToKey=" + valueToKey + "]";
    }

}

Надеемся, что это поможет некоторым элементарным потребностям Двунаправленной Мульти Карта. Обратите внимание, что K и V должны правильно реализовать метод hascode и equals

Ответ 5

Надеюсь, я понял тебя.

class A {
    long id;
    List<B> bs;
}

class B {
    long id;
    List<A> as;
}

Ответ 6

Реализация Google Guava MultiMap - это то, что я использую для этих целей.

Map<Key Collection<Values>> 

где Collection может быть, например, ArrayList. Он позволяет сопоставить несколько значений, хранящихся в коллекции, с ключом. Надеюсь, это поможет!