【问题标题】:What's an efficient way to store data, access it with keys and iterate a subpart of it based on the values?存储数据、使用键访问数据并根据值迭代数据的子部分的有效方法是什么?
【发布时间】:2015-05-07 21:17:37
【问题描述】:

我有一个类集合,其中存储了一些我需要执行以下操作的数据:

  • 使用一些唯一 ID 频繁访问数据
  • 根据类属性的非唯一有序值访问集合子部分的数据

你能想出在 Java 中实现这一点的任何有效方法吗?


首先,我想到了使用以 id 作为键的 HashMap

  • 一个HashMap是O(1)从key中获取数据;
  • 它可以按值排序,但当您想要获得特定值时效率低下(整个集合被迭代);

然后,我想到了使用 TreeMap,以有序值作为键

  • TreeMap 允许对有序值进行高效迭代;
  • 有序值不是唯一的,因此它应该是 TreeMultimap;
  • 但从其 id 获取值将是 O(log(n));

同时使用这两个结构似乎也不是一个好的解决方案,因为它们必须同步。我猜某种 BiMultiMap 对其值进行排序并从特定值开始对其进行迭代可以解决我的问题,但我找不到这样做的方法。


我试图制作一个例子来说明我的需求。这个火车的东西不是我的实际问题,我试着让它不那么抽象。

public static class Train implements Comparable<Train> {
    String id;
    int maxSpeed;
    String trainColor;

    public Train(String id, int d1, String d2){
        this.id = id;
        this.maxSpeed = d1;
        this.trainColor = d2;
    }

    @Override
    public String toString() {
        return id + " = (" + maxSpeed + ", " + trainColor + ")";
    }

    @Override 
    public int compareTo(Train o) {
        return Integer.compare(this.maxSpeed, o.maxSpeed);
    }
}

public static void main(String[] args){
    // Let's say I need two things:
    //   - the trains that can go higher than a certain speed
    //   - the train data of a particular train
    int start = 3;
    String seekedId = "FlyingScotman";

    Train d1 = new Train("HogwartExpress", 5, "blue");
    Train d2 = new Train("TGV", 4, "red");
    Train d3 = new Train("FlyingScotman", 3, "blue");
    Train d4 = new Train("OrientExpress", 2, "black");
    Train d5 = new Train("Trans-Siberian", 1, "grey");

    /******* HashMap implementation *******/

    Map<String, Train> hashMapData = new HashMap<String, Train>();
    hashMapData.put(d1.id, d1);
    hashMapData.put(d2.id, d2);
    hashMapData.put(d3.id, d3);
    hashMapData.put(d4.id, d4);
    hashMapData.put(d5.id, d5);
    hashMapData = MapUtil.sortByValue(hashMapData);

    // Bad: I have to iterate the whole collection to reach the subcollection
    System.out.println("\n>>>>>>> HashMap: subcollection");
    for(Map.Entry<String, Train> entry : hashMapData.entrySet()) {
        if (entry.getValue().maxSpeed < start) {
            continue;
        }
        System.out.println(entry.getValue());
    }

    // Good: I get my data directly
    System.out.println("\n>>>>>>> HashMap: get");
    System.out.println(hashMapData.get(seekedId));

    /******* TreeMap implementation *******/

    TreeMap<Integer, Train> treeMapData = new TreeMap<Integer, Train>();
    treeMapData.put(d1.maxSpeed, d1);
    treeMapData.put(d2.maxSpeed, d2);
    treeMapData.put(d3.maxSpeed, d3);
    treeMapData.put(d4.maxSpeed, d4);
    treeMapData.put(d5.maxSpeed, d5);

    // Good: I can iterate a subcollection efficiently
    System.out.println(">>>>>>> TreeMap: subcollection");
    for(Map.Entry<Integer, Train> entry : treeMapData.tailMap(start).entrySet()) {
        System.out.println(entry.getValue());
    }

    System.out.println("\n>>>>>>> TreeMap: get");
    // Bad: I have to iterate the whole collection to reach the data
    for(Map.Entry<Integer, Train> entry: treeMapData.entrySet()) {
        if (entry.getValue().id.equals(seekedId)) {
            System.out.println(entry.getValue());
        }
    }

    // Also bad: the values used as keys might not be unique

}

输出

>>>>>>> TreeMap: subcollection
FlyingScotman = (3, blue)
TGV = (4, red)
HogwartExpress = (5, blue)

>>>>>>> TreeMap: get
FlyingScotman = (3, blue)

>>>>>>> HashMap: subcollection
FlyingScotman = (3, blue)
TGV = (4, red)
HogwartExpress = (5, blue)

>>>>>>> HashMap: get
FlyingScotman = (3, blue)

MapUtil.sortByValue 方法由 Carter Page 提供:Sort a Map<Key, Value> by values (Java)

先谢谢了,如果有什么不清楚的地方请告诉我。

【问题讨论】:

  • 一个(如果需要,在内存中)数据库?
  • 我的意思是如何将它存储在本地,每次我需要某些东西时都访问数据库不会让它更快,会不会......?
  • 您需要多张地图,stackoverflow.com/questions/822322/…。如果您有非唯一键,请查看 guava Multimap 和 TreeMultimap。但正如之前建议的那样,mem db 非常方便且非常快。

标签: java iterator hashmap treemap linkedhashmap


【解决方案1】:

您可以为实现MapHashMap 创建包装类,并添加一个排序集来存储值。 Guava TreeMultiset 应该很好,因为它允许具有相同顺序的元素。

它看起来像数据库中的索引。您将以较慢的修改为代价获得更快的读取操作。

public class MyMap<K, V extends Comparable<V>> implements Map<K, V> {
  private HashMap<K, V> hashMap = new HashMap<K, V>();
  private TreeMultiset<V> treeMultiset = TreeMultiset.create();

  // delegate all Map methods to hashMap
  // delegate subset methods to treeMultiset
  // all mutators should make corresponding modifications to treeMultiset
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-12
    • 1970-01-01
    • 2014-02-17
    • 2011-06-05
    相关资源
    最近更新 更多