从集合中获取对象而不在java中循环

从集合中获取对象而不在java中循环,java,optimization,collections,Java,Optimization,Collections,我需要重复(几十万次)从包含数万个对象的集合中检索一个元素(每次都不同) 执行此检索操作的最快方法是什么?目前,我的集合是一个列表,我在上面迭代,直到找到元素,但是有没有更快的方法?使用地图可能吗?我在想: 将对象放入映射中,键是对象的id字段,对象本身是值 然后在映射上执行get(id)应该比在列表中循环快得多 如果这是正确的方法,我应该使用HashMap还是TreeMap我的对象没有特定的顺序 如果您对此事有任何建议,我们将不胜感激 最后一点:如果一个外部库提供了一个工具来回答这个问题,

我需要重复(几十万次)从包含数万个对象的
集合中检索一个元素(每次都不同)

执行此检索操作的最快方法是什么?目前,我的
集合
是一个
列表
,我在上面迭代,直到找到元素,但是有没有更快的方法?使用
地图
可能吗?我在想:

  • 将对象放入
    映射中
    ,键是对象的id字段,对象本身是值
  • 然后在
    映射上执行
    get(id)
    应该比在
    列表中循环快得多
    
  • 如果这是正确的方法,我应该使用
    HashMap
    还是
    TreeMap
    我的对象没有特定的顺序
如果您对此事有任何建议,我们将不胜感激


最后一点:如果一个外部库提供了一个工具来回答这个问题,我很乐意接受

根据(我自己的)重点文件:

地图根据其键的自然顺序进行排序, 或者由在地图创建时提供的比较器执行,具体取决于 使用构造函数

在您的情况下,您声明这些项目没有特定的顺序,并且似乎并不追求任何特定的顺序,而是能够尽可能快地检索数据

HashMaps
提供恒定的读取时间,但不保证顺序,因此我认为您应该使用
HashMaps

此类不保证地图的顺序;在里面 特别是,它不能保证订单保持不变 随着时间的推移此实现为提供恒定的时间性能 基本操作(get和put),假设为哈希函数 将元素正确分散在桶中


顺便说一句,它的内存占用可能会很快变得很高,因此研究数据库方法并使用类似缓存的机制来处理更频繁使用的信息也可能是一个好主意。

如果您有很好的方法来定义映射的键,您可以使用映射。在最坏的情况下,可以将对象用作键和值


由于排序不重要,请使用
哈希映射
。要在
树映射中保持顺序,添加元素时需要额外的成本,因为它必须添加到正确的位置。

HashMap通常效率更高,所以只要不关心键的顺序,就使用它


当您希望在Map中按键对条目进行排序时,请使用TreeMap,但在您的情况下,排序将是开销,因为您不需要任何微粒顺序。

我创建了代码,用于测试给定问题的BinarySearch、TreeMap和HashMap的形式

在每次重建集合时,HashMap是最快的(即使使用标准对象的hashCode()实现!),sort+array二进制搜索排在第二位,TreeMap排在最后(由于重建过程复杂)

如果不重建集合,HashMap仍然是最快的,数组的二进制搜索是第二位,TreeMap是最慢的,但速度仅略低于数组

proc array: 506
proc tree : 561
proc hash : 122
测试代码:

public class SearchSpeedTest {

    private List<DataObject> data;
    private List<Long> ids;
    private Map<Long, DataObject> hashMap;
    private Map<Long, DataObject> treeMap;
    private int numRep;
    private int dataAmount;
    private boolean rebuildEachTime;

    static class DataObject implements Comparable<DataObject>{
        Long id;

        public DataObject(Long id) {
            super();
            this.id = id;
        }

        public DataObject() {
            // TODO Auto-generated constructor stub
        }

        @Override
        public final int compareTo(DataObject o) {
            return Long.compare(id, o.id);
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public void dummyCode() {

        }

    }

    @FunctionalInterface
    public interface Procedure {
        void execute();
    }

        public void testSpeeds() {

            rebuildEachTime = true;
            numRep = 100;
            dataAmount = 60_000;

            data = new ArrayList<>(dataAmount);
            ids = new ArrayList<>(dataAmount);
            Random gen = new Random();

            for (int i=0; i< dataAmount; i++) {
                long id = i*7+gen.nextInt(7);
                ids.add(id);
                data.add(new DataObject(id));
            }
            Collections.sort(data);


            treeMap = new TreeMap<Long, DataObject>();
            populateMap(treeMap);


            hashMap = new HashMap<Long, SearchSpeedTest.DataObject>();
            populateMap(hashMap);


            Procedure[] procedures = new Procedure[] {this::testArray, this::testTreeMap, this::testHashMap}; 
            String[] names = new String[]                {"array",       "tree ",            "hash "};


            for (int n=0; n<procedures.length; n++) {
                Procedure proc = procedures[n];
                long startTime = System.nanoTime();
                for (int i=0; i<numRep; i++) {
                    if (rebuildEachTime) {
                        Collections.shuffle(data);
                    }
                    proc.execute();
                }
                long endTime = System.nanoTime();
                long diff = endTime - startTime;

                System.out.println("proc "+names[n]+":\t"+(diff/1_000_000));
            }

        }

        void testHashMap() {
            if (rebuildEachTime) {
                hashMap = new HashMap<Long, SearchSpeedTest.DataObject>();
                populateMap(hashMap);
            }

            testMap(hashMap);
        }

        void testTreeMap() {

            if (rebuildEachTime) {
                treeMap = new TreeMap<Long, SearchSpeedTest.DataObject>();
                populateMap(treeMap);
            }

            testMap(treeMap);
        }

        void testMap(Map<Long, DataObject> map) {

            for (Long id: ids) {
                DataObject ret = map.get(id);
                ret.dummyCode();
            }

        }

        void populateMap(Map<Long, DataObject> map) {
            for (DataObject dataObj : data) {
                map.put(dataObj.getId(), dataObj);
            }
        }

        void testArray() {
            if (rebuildEachTime) {
                Collections.sort(data);
            }
            DataObject key = new DataObject();
            for (Long id: ids) {
                key.setId(id);
                DataObject ret = data.get(Collections.binarySearch(data, key));
                ret.dummyCode();
            }
        }

        public static void main(String[] args) {
            new SearchSpeedTest().testSpeeds();
        }
    }
公共类SearchSpeedTest{
私人名单数据;
私有列表ID;
私有映射hashMap;
私有地图树图;
私人国际货币基金组织;
私人int数据量;
私有布尔重建时间;
静态类DataObject实现了可比较的{
长id;
公共数据对象(长id){
超级();
this.id=id;
}
公共数据对象(){
//TODO自动生成的构造函数存根
}
@凌驾
公共最终整数比较(数据对象o){
返回Long.compare(id,o.id);
}
公共长getId(){
返回id;
}
公共无效集合id(长id){
this.id=id;
}
公共空间dummyCode(){
}
}
@功能接口
公共接口程序{
void execute();
}
公共void testSpeeds(){
重建时间=真;
numRep=100;
数据量=60_000;
数据=新的ArrayList(数据量);
ids=新的ArrayList(数据量);
Random gen=新的Random();
对于(int i=0;ifor(int n=0;n如何确定要检索哪个元素?其他一切都取决于此。TreeMap根据定义的比较器对数据进行排序。使用
HashMap
TreeMap
的优劣取决于您的实现。情况如下:网络由节点之间的关系组成(源和目标)。我有一组关系。关系是一个具有字段字符串“source”(节点源的id)和字段字符串“target”(节点目标的id)的对象.Relations还有其他字段。对于每个关系,我需要检索源节点和目标节点。这些节点保存在单独的集合中。但是如果OP使用
set
,不循环访问元素是不可能的,不是吗?因为OP似乎不关心排序,所以需要使用
HashMap
public class SearchSpeedTest {

    private List<DataObject> data;
    private List<Long> ids;
    private Map<Long, DataObject> hashMap;
    private Map<Long, DataObject> treeMap;
    private int numRep;
    private int dataAmount;
    private boolean rebuildEachTime;

    static class DataObject implements Comparable<DataObject>{
        Long id;

        public DataObject(Long id) {
            super();
            this.id = id;
        }

        public DataObject() {
            // TODO Auto-generated constructor stub
        }

        @Override
        public final int compareTo(DataObject o) {
            return Long.compare(id, o.id);
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public void dummyCode() {

        }

    }

    @FunctionalInterface
    public interface Procedure {
        void execute();
    }

        public void testSpeeds() {

            rebuildEachTime = true;
            numRep = 100;
            dataAmount = 60_000;

            data = new ArrayList<>(dataAmount);
            ids = new ArrayList<>(dataAmount);
            Random gen = new Random();

            for (int i=0; i< dataAmount; i++) {
                long id = i*7+gen.nextInt(7);
                ids.add(id);
                data.add(new DataObject(id));
            }
            Collections.sort(data);


            treeMap = new TreeMap<Long, DataObject>();
            populateMap(treeMap);


            hashMap = new HashMap<Long, SearchSpeedTest.DataObject>();
            populateMap(hashMap);


            Procedure[] procedures = new Procedure[] {this::testArray, this::testTreeMap, this::testHashMap}; 
            String[] names = new String[]                {"array",       "tree ",            "hash "};


            for (int n=0; n<procedures.length; n++) {
                Procedure proc = procedures[n];
                long startTime = System.nanoTime();
                for (int i=0; i<numRep; i++) {
                    if (rebuildEachTime) {
                        Collections.shuffle(data);
                    }
                    proc.execute();
                }
                long endTime = System.nanoTime();
                long diff = endTime - startTime;

                System.out.println("proc "+names[n]+":\t"+(diff/1_000_000));
            }

        }

        void testHashMap() {
            if (rebuildEachTime) {
                hashMap = new HashMap<Long, SearchSpeedTest.DataObject>();
                populateMap(hashMap);
            }

            testMap(hashMap);
        }

        void testTreeMap() {

            if (rebuildEachTime) {
                treeMap = new TreeMap<Long, SearchSpeedTest.DataObject>();
                populateMap(treeMap);
            }

            testMap(treeMap);
        }

        void testMap(Map<Long, DataObject> map) {

            for (Long id: ids) {
                DataObject ret = map.get(id);
                ret.dummyCode();
            }

        }

        void populateMap(Map<Long, DataObject> map) {
            for (DataObject dataObj : data) {
                map.put(dataObj.getId(), dataObj);
            }
        }

        void testArray() {
            if (rebuildEachTime) {
                Collections.sort(data);
            }
            DataObject key = new DataObject();
            for (Long id: ids) {
                key.setId(id);
                DataObject ret = data.get(Collections.binarySearch(data, key));
                ret.dummyCode();
            }
        }

        public static void main(String[] args) {
            new SearchSpeedTest().testSpeeds();
        }
    }