Java多对多关联映射

时间:2010-04-03 15:24:23

标签: java hashmap structure many-to-many associations

我必须上课, ClassA ClassB 以及“多对多” AssociationClass 。我想使用一个结构来保存A和B之间的关联,例如我可以知道,对于A或B的每个实例,它们都是它们的对应物。

我想过使用带有对密钥的Hashmap:

Hasmap<Pair<ClassA, ClassB>, AssociationClass> associations;

这样,我可以添加和删除 ClassA ClassB 的两个实例之间的关联,我可以查询两个给定实例的关系。

但是,我错过了为 ClassA ClassB 的给定实例定义所有关联的功能。

我可以通过暴力破解并遍历地图的所有键来搜索给定实例之间的关联,但这样效率低且不优雅。

您知道任何支持此功能的数据结构/免费库吗?我不想重新发明轮子。

先谢谢你的帮助,

圣拉斐尔

NB :这不是“数据库”问题。这些对象是用于实时计算的纯POJO,我不需要持久化的东西。

7 个答案:

答案 0 :(得分:4)

这是我基于番石榴Multimap的实现:

public class ImmutableBiMultimap<K, V> {
    private final ImmutableSetMultimap<K, V> kToV;
    private final ImmutableSetMultimap<V, K> vToK;

    public ImmutableBiMultimap (SetMultimap<K, V> keyToValueMap) {
        kToV = ImmutableSetMultimap.copyOf(keyToValueMap);

        SetMultimap<V, K> valueToKeyMap = HashMultimap.create();
        for (Entry<K, V> entry : kToV.entries()) {
            valueToKeyMap.put(entry.getValue(), entry.getKey());
        }

        vToK = ImmutableSetMultimap.copyOf(valueToKeyMap);
    }

    public ImmutableSet<V> getValuesForKey(K key) {
        return kToV.get(key);
    }

    public ImmutableSet<K> getKeysForValue(V value) {
        return vToK.get(value);
    }
}

答案 1 :(得分:3)

感谢您的建议。

我终于重新发明了轮子...... 我写了一个关于持有关联的泛型类。 我使用两张地图地图,同步。

协会持有人提供以下方法

void setAssociation(LeftClass left, RightClass right, AssociationClass assoc);
AssociationClass getAssociation(LeftClass left, RightClass right);
Map<RightClass, AssociationClass> getAssocationsLeft(LeftClass left);
Map<LeftClass, AssociationClass> getAssocationsRight(RightClass right); 
void removeAssociation(LeftClass left, RightClass right);

以下是代码:

import java.util.HashMap;

/** This class holds many to many associations between two classes. */
public class AssociationHolder<LeftClass, RightClass, AssociationClass> {

    // -------------------------------------------------------
    // Attributes
    // -------------------------------------------------------

    private HashMap<LeftClass, HashMap<RightClass, AssociationClass>> associationsLeft = 
        new HashMap<LeftClass, HashMap<RightClass,AssociationClass>>();
    private HashMap<RightClass, HashMap<LeftClass, AssociationClass>> associationsRight = 
        new HashMap<RightClass, HashMap<LeftClass,AssociationClass>>();     

    // -------------------------------------------------------
    // Methods
    // -------------------------------------------------------

    /** 
     *  Set an association between two instance.
     *  Any prior association is overwritten.
     */
    public void setAssociation(LeftClass left, RightClass right, AssociationClass association) {

        // Get the map for the left 
        HashMap<RightClass, AssociationClass> leftMap = this.associationsLeft.get(left);

        // No association defined yet for this left key ? => Create new map
        if (leftMap == null) {
            leftMap = new HashMap<RightClass, AssociationClass>();
            this.associationsLeft.put(left, leftMap);
        }

        // Get the map for the right 
        HashMap<LeftClass, AssociationClass> rightMap = this.associationsRight.get(right);

        // No association defined yet for this right key ? => Create new map
        if (rightMap == null) {
            rightMap = new HashMap<LeftClass, AssociationClass>();
            this.associationsRight.put(right, rightMap);
        }

        // Set the assoication on both maps
        leftMap.put(right, association);
        rightMap.put(left, association);        

    } 

    /** @return null if no association found. */
    public AssociationClass getAssociation(LeftClass left, RightClass right) {

        // Use left maps (could have used the right one as well)
        HashMap<RightClass, AssociationClass> leftMap = this.associationsLeft.get(left);
        if (leftMap == null) return null;
        return leftMap.get(right);
    }

    /** Get all associations defined for a given Left instance.  */
    public HashMap<RightClass, AssociationClass> getAssociationsLeft(LeftClass left) {

        HashMap<RightClass, AssociationClass> leftMap = this.associationsLeft.get(left);

        // No map defined ? return empty one instead of null
        if (leftMap == null) {
            return new HashMap<RightClass, AssociationClass>();
        } else {
            return leftMap;
        }   
    }

    /** Get all associations defined for a given Right instance.  */
    public HashMap<LeftClass, AssociationClass> getAssociationsRight(RightClass right) {

        HashMap<LeftClass, AssociationClass> rightMap = this.associationsRight.get(right);

        // No map defined ? return empty one instead of null
        if (rightMap == null) {
            return new HashMap<LeftClass, AssociationClass>();
        } else {
            return rightMap;
        }   
    }

    /** 
     *  Remove an association between two instances.
     */
    public void removeAssociation(LeftClass left, RightClass right) {
        HashMap<RightClass, AssociationClass> leftMap = this.getAssociationsLeft(left);
        HashMap<LeftClass, AssociationClass> rightMap = this.getAssociationsRight(right);
        leftMap.remove(right);      
        rightMap.remove(left);  
    }
}

我希望这可以在将来帮助某人。

答案 2 :(得分:1)

也许来自Google Collections Library的Multimap或BiMap可以满足您的需求。

答案 3 :(得分:1)

这看起来像是一个问题,在这个问题中,您希望使用多个密钥获取数据。您想要按ClassA和ClassB进行搜索。这通常会导致数据顶上的多个映射,以便每个映射都将搜索关键字保存到基础数据中。也许这样的事情会起作用:

public class Data {

  public ClassA a;
  public ClassB b;
  public AssociationClass association;

}

Map<ClassA, Data> aData;
Map<ClassB, Data> bData;
Map<AssociationClass, Data> associationData;

插入如下:

Data data = new Data()

aData.put(data.a, data);
bData.put(data.b, data);
associationData.put(data.association, data);

获取数据,您可以查询每个地图以获得您想要的数据。您甚至可以将Pair类作为数据的另一个索引:

Map<Pair<ClassA, ClassB>, Data> pairData;

这种方法的问题在于,如果底层数据发生了很大变化,您必须确保所有地图都是同步的。如果这主要是一个只读问题,那么你创建地图,然后只用你的密钥查询数据。

答案 4 :(得分:0)

使用您的AssociationClass,您可以让ClassA和ClassB都包含对AssociationClass的引用:

private AssociationClass association;

或者,另一种方法......

ClassA可以包含:

private List<ClassB> classBList;

和ClassB可以包含:

private List<ClassA> classAList;

通过实现此功能,您可以从关联的类中访问您的关联。

答案 5 :(得分:0)

rmarimon是对的,它需要两张地图,但我认为你想要A-B,而不是A数据和B数据。

所以你只需要两张地图:


    Hashmap bByA = new HashMap();
    Hashmap aByB = new HashMap();

这为您提供了您想要的一切,既自由又轻松。

答案 6 :(得分:0)

为什么不在每个班级中放置一张地图?

class ClassA {
    ...
    private Map<ClassB, AssociationClass> associations
            = HashMap<ClassB, AssociationClass>();
    ...
}

class ClassA {
    ...
    private Map<ClassA, AssociationClass> associations
            = HashMap<ClassB, AssociationClass>();
    ...
}