小编典典

Java中的多级映射

java

在Java中将值(“ o”)保留在像这样的树结构中的最佳方法是什么:

                    obj1                 
                     /\
                    /  \
                   /    \
              obj2        obj3
              /\            /\
             /  \          /  \
            /    \        /    \
          obj4  obj5    obj6   obj7
          /\     /\     /\      /\
         /  \   /  \   /  \    /  \
        o8   oN...

它看起来像一棵树,但是我不需要任意深度。我宁愿需要强大的数据类型和预定义的美观方法来处理最终结构。

我需要能够通过键获取某种值列表-就像在我的图片上一样。换句话说,结构应 以任何方式变得平坦。

我需要.get(obj3)回来{obj6, obj7}, .get(obj1) - {obj2, obj3}

现在,我使用Map来实现此功能,但是由于需要检查结构的每个级别,因此夸大此类地图是很丑陋的。看起来像这样( 数据 就是地图):

if(data.get(somedouble) == null) {
    Map<Integer, Data> inm = new TreeMap<>();
    inm.put(someint, obj);
    Map<Double, Map<Integer, Data>> m = new TreeMap<>();
    m.put(somedouble2, inm);
    data.put(somedouble, m);
}
else {
    if(data.get(somedouble).get(somedouble2) == null) {
        Map<Integer, Data> inm = new TreeMap<>();
        inm.put(someint, obj);
        data.get(somedouble).put(somedouble2, inm);
    }
    else
        data.get(somedouble).get(somedouble2).put(someint, obj);
}

性能不是问题,但是代码美才是。


阅读 225

收藏
2020-11-13

共1个答案

小编典典

您可以使用您的特定密钥:

class MyKey {
    Double beta;
    Double yaw;
    int minute;

    public int hashCode() {
        /* Returns hash code from a combination of hash of the key members. */
    }

    @Override
    public boolean equals(Object obj) {
        /* Returns true if obj is a MyKey with same members. */
    }
}

然后简单地:

data.put(myKey, obj);

这样,“多级检查”全部隐藏在中MyKey.equals()。它可以使客户端代码保持干净,并且关键的复杂性放在安全的地方。

需求更改后进行编辑:

如果最重要的是,您希望能够获得从双beta精度对象到对象的映射,那么我仍然会像这样保持平面。

您真正想要的是为数据提供多个“索引”(例如在数据库中),以便您可以查询具有相同“ beta”或“
yaw”的对象。为此,最好的方法是使用多个Map(实际上是Multimap),每个“索引”使用一个。

使用番石榴的Multimap

ListMultimap<Double, Data> mapForBeta;
ListMultimap<Double, Data> mapForYaw;

您可以将所有的multimap和Map<MyKey, Data>放在您的特定类中。实际上,最好的方法是子类化Map<MyKey, Data>

public class MyMap extends HashMap<MyKey, Data> {

    ListMultimap<Double, Data> mapForBeta;
    ListMultimap<Double, Data> mapForYaw;


    public Data put(MyKey key, Data value) {
        super.put(key, value);
        mapForBeta.add(key.beta, value);
        mapForYaw.add(key.yaw, value);
    };

    public List<Data> getFromBeta(Double beta) {
        return mapForBeta.get(beta);
    }

    public List<Data> getFromYaw(Double yaw) {
        return mapForYaw.get(yaw);
    }
}

具有更好解决方案的新编辑:

实际上,这让我开始思考,我意识到您的地图默认值确实存在问题,这就是为什么您的代码有点混乱的原因。

您可以使用生成器来创建基础地图的默认地图来解决此问题:

public class DefaultMap<K, V> extends TreeMap<K, V> {

    static abstract class Generator<V>{
        abstract V create();
    }

    final Generator<V> generator;


    DefaultMap(Generator<V> generator) {
        this.generator = generator;
    }

    @Override
    public V get(Object key) {
        V val = super.get(key);
        if (val == null) {
            val = generator.create();

            put((K)key, val);
        }

        return val;
    }
}

现在,您可以使用实用程序树类来存储所有数据:

public class MyTree {
  private final Map<Double, Map<Double, Map<Integer, Data>>> data;

  public MyTree() {
    data = new DefaultMap<>(new Generator<Map<Double, Map<Integer, Data>>>() {
      @Override
      Map<Double, Map<Integer, Data>> create() {
        return new DefaultMap<>(new Generator<Map<Integer, Data>>() {

          @Override
          Map<Integer, Data> create() {
            return new TreeMap<>();
          }

        });
      }
    });
  }

  void add(MyKey d, Data obj) {
    data.get(d.beta).get(d.yaw).put(d.minute, obj);
  }
}

现在,您可以使用data.get(beta).get(yaw)访问数据,并且没有意大利面条代码来存储您的值。

2020-11-13