【问题标题】:Bidirectional multi-valued map in JavaJava中的双向多值映射
【发布时间】:2011-11-09 14:01:28
【问题描述】:

我正在寻找一种存储键值对的方法。我需要查找是双向的,但同时我需要为同一个键存储多个值。换句话说,类似于 BidiMap,但每个键都可以有多个值。例如,它需要能够保存如下对:“s1”->1、“s2”->1、“s3”->2,并且我需要能够获取映射到每个键的值,并且对于每个值,获取与其关联的所有键。

【问题讨论】:

  • 您谈到每个键需要多个值,但在您的示例中,您没有具有多个值的键,而是一个具有两个键的值。您可能应该澄清这一点。如果你的例子适合你的问题,你会得到更好的答案;-)
  • jguru.com/faq/view.jsp?EID=1317828在这里你可以找到如何创建多图
  • @pushy,同样的问题,如果我反转映射,并将整数作为键而不是值,我会得到一个一对多的映射。不管怎样,谢谢指正。 :)

标签: java multimap


【解决方案1】:

所以您需要支持多对多关系吗?最接近的是GuavaMultimap,就像@Mechkov 写的那样——但更具体地说是MultimapMultimaps.invertFrom 的组合。 “BiMultimap”尚未实现,但在 Google Guava 库中有 an issue 请求此功能。

此时你有几个选择:

  1. 如果您的“BiMultimap”将成为不可变常量 - 使用 Multimaps.invertFromImmutableMultimap / ImmutableListMultimap / ImmutableSetMultimap(这三个中的每一个都有不同的集合存储值)。一些代码(取自我开发的应用程序的示例,使用Enums 和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));
        }
    }
    
  2. 如果你真的希望你的 Multimap 是可修改的,那么很难同时维护 K->V 和 V->K 变体,除非你只修改 kToVMultimap 并在每次调用想要拥有它的倒置副本(并使该副本不可修改,以确保您不小心不修改vToKMultimap 不会更新kToVMultimap 的内容)。这不是最佳的,但在这种情况下应该这样做。

  3. (可能不是你的情况,作为奖励提到):BiMap 接口和实现类具有.inverse() 方法,该方法从BiMap&lt;K, V&gt;biMap.inverse().inverse() 之后提供BiMap&lt;V, K&gt; 视图。如果我之前提到的this issue完成了,它可能会有类似的东西。

  4. (2016 年 10 月编辑)您还可以使用 new graph API,它将出现在 Guava 20 中:

    作为一个整体,common.graph 支持以下种类的图:

    • 有向图
    • 无向图
    • 具有相关值(权重、标签等)的节点和/或边
    • 允许/不允许自循环的图表
    • 允许/不允许平行边的图(具有平行边的图有时称为多重图)
    • 节点/边按插入顺序、排序或无序排列的图

【讨论】:

    【解决方案2】:

    有两个映射,key->values,values->keys有什么问题?

    【讨论】:

    • 我认为保留相同数据的两个副本会更容易出错。无论如何,在我看过所有系列之后,我开始认为这是最好的解决方案。
    • 只需为地图创建一个包装器,使它们保持同步。
    • 我不喜欢这个答案所认可的方法。这有很多潜在的问题,包括可能重新发明轮子、在此过程中编写自己的错误、线程安全等。
    【解决方案3】:

    我希望使用 MultivaluedMap 可以解决问题。 请在下面的链接中找到来自 oracle 的文档。

    http://docs.oracle.com/javaee/6/api/javax/ws/rs/core/MultivaluedMap.html

    【讨论】:

    • 这是一个接口。有实现吗?
    【解决方案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。它允许将存储在集合中的多个值映射到一个键。 希望这会有所帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-11-15
        • 1970-01-01
        • 2015-04-22
        • 1970-01-01
        • 2015-08-22
        • 2010-11-14
        • 2010-11-07
        相关资源
        最近更新 更多