Java中的多级映射 [英] Multilevel map in Java

查看:16
本文介绍了Java中的多级映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Java 中将值(o")保存在这样的树结构中的最佳方法是什么:

What is the best way in Java to keep values ("o") in a tree structure like this:

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

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

It looks like a tree, but I don't need arbitrary depth. I rather need strong datatyping and predefined good looking methods for working with final structure.

我需要能够通过键获得某种值列表 - 就像我的图片一样.换句话说,结构不应该以任何方式变成平面.

I need to be able to get some kind of list of values by keys - exactly like on my picture. In other words, structure should not become planar in any way.

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

现在我使用 Map 来做这件事,但是膨胀这样的地图很难看,因为我需要检查结构的每个级别.看起来像这样(数据是地图):

For now I use Map for that, but inflating such map is ugly, because I need to check each level of the structure. Looks like that (data is the 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);
}

性能不是问题,代码美才是问题.

Performance in not an issue, but code beauty is.

推荐答案

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

You can use your specific key:

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()中.它使客户端代码保持干净,并将关键的复杂性放在一个安全的地方.

This way the "multi-level checks" are all hidden in MyKey.equals(). It keeps the client code clean and the key complexity is in a safe place.

如果最重要的是,您希望能够获得从双 beta 到您的对象的地图,那么我仍然会保持这样的平面.

If on top of this, you want to be able to have a map from your double beta to your objects, then I would still keep the thing planar like that.

您真正想要的是为您的数据创建多个索引",就像在数据库中一样,这样您就可以查询具有相同beta"或yaw"的对象.为此,最好的方法是使用多个 Map(实际上是 Multimap),每个索引"一个.

What you actually want is to have multiple "indexes" for your data, like in a database, so you can query for objects with same "beta" or "yaw". For that the best way is to use several Map (actually Multimap), one for each of your "indexes".

使用 Guava 的 Multimap:

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

您可以将所有多图和 Map 放在您的特定类中.实际上最好的方法是子类化 Map:

You can put all the multimap and the Map<MyKey, Data> in your a specific class. Actually the best way would be to subclass 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);
    }
}

具有更好解决方案的新

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

New Edit with better solution:

Actually, it got me thinking, and I realized that you are really having a problem with default values for your maps, and that's why your code is a bit messy.

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

You can solve this with a Default Map using a generator to create underlying maps:

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;
    }
}

现在你可以让你的工具树类来存储你的所有数据:

Now you can have your utility tree class to store all your data :

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) 访问您的数据,并且您没有意大利面条代码来存储您的值.

Now you can access your data with data.get(beta).get(yaw) and you don't have spaghetti code to store your values.

这篇关于Java中的多级映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆