如何加快我的ArrayList搜索?

时间:2011-09-27 12:51:03

标签: java performance collections arraylist

我目前有一个ArrayList持有我创建的类的对象,然后在ArrayList搜索中解析for loop并比较来自ArrayList的一些数据还有一些全局variables加载到其他位置,但是这个ArrayList不断增长,并且最终会有大约115个元素到达终点,然后需要很长时间来搜索,函数对于我从文本文件中读取的每一行,这也会调用一次,文本文件通常大约为400-500行,因此即使在测试小文件时也可以判断它是非常慢的过程。有没有办法通过使用另一个collection而不是ArrayList来加快速度,我使用ArrayList的理由是我必须知道它找到时的索引是什么匹配。

这是班级:

private ArrayList<PanelData> panelArray = new ArrayList<PanelData>(1);

    public class PanelData {
        String dev = "";
        String inst = "";
        double tempStart = 0.0;
        double tempEnd = 0.0;
    }

功能:

public void panelTimeHandler (double timeStart, double timeEnd) throws SQLException {   
        PanelData temps = new PanelData();
        temps.dev = devIDStr;
        temps.inst = instanceStr;
        temps.tempStart = timeStart;
        temps.tempEnd = timeEnd;
        boolean flag = false;

        if(!flag)
        {
            panelArray.add(temps);
            flag = true;
        }

        for(int i = 0; i < panelArray.size(); ++i ) {
            if(panelArray.get(i).dev.equals(devIDStr) && panelArray.get(i).inst.equals(instanceStr)) {
                if(panelArray.get(i).tempStart <= timeStart  && panelArray.get(i).tempEnd >= timeEnd ) {
                    //Do Nothing
                }
                else 
                {
                    temps.dev = devIDStr;
                    temps.inst = instanceStr;
                    temps.tempStart = timeStart;
                    temps.tempEnd = timeEnd;
                    insert();
                    panelArray.set(i, temps);
                }
            }
            else
            {
                temps.dev = devIDStr;
                temps.inst = instanceStr;
                temps.tempStart = timeStart;
                temps.tempEnd = timeEnd;
                panelArray.add(temps);
                insert();
            }
        }
    }

如果还有更多你想看到的东西,谢谢。牛肉。

更新:添加了insert()函数

private void insert() throws SQLException
{
    stmt = conn.createStatement();  

    String sqlStm = "update ARRAY_BAC_SCH_Schedule set SCHEDULE_TIME = {t '" + finalEnd + "'} WHERE SCHEDULE_TIME >=  {t '" + finalStart + "'} AND" +
        " SCHEDULE_TIME <=  {t '" + finalEnd + "'} AND VALUE_ENUM = 0 AND DEV_ID = " + devIDStr + " and INSTANCE = " + instanceStr;
    int updateSuccess = stmt.executeUpdate(sqlStm);

    if (updateSuccess < 1)
    {   
        sqlStm = "insert into ARRAY_BAC_SCH_Schedule (SITE_ID, DEV_ID, INSTANCE, DAY, SCHEDULE_TIME, VALUE_ENUM, Value_Type) " +
                " values (1, " + devIDStr + ", " + instanceStr + ", " + day + ", {t '" + finalStart + "'}, 1, 'Unsupported')";
        stmt.executeUpdate(sqlStm);
        sqlStm = "insert into ARRAY_BAC_SCH_Schedule (SITE_ID, DEV_ID, INSTANCE, DAY, SCHEDULE_TIME, VALUE_ENUM, Value_Type) " +
                " values (1," + devIDStr + ", " + instanceStr + ", " + day + ", {t '" + finalEnd + "'}, 0, 'Unsupported')";
        stmt.executeUpdate(sqlStm);
    }
    if(stmt!=null)
        stmt.close();
}

更新

感谢Matteo,我意识到我正在添加数组,即使我没有找到匹配,直到第10个元素,然后它将添加到数组前9次,这会在数组中创建许多额外的元素,这就是为什么它是如此之慢,我添加了一些休息并在功能中做了一些调整,它提高了很多性能。感谢所有输入

5 个答案:

答案 0 :(得分:3)

您可以使用LinkedHashSet。看起来你只在列表的末尾添加了元素,这正是LinkedHashSet在插入元素时的作用。
但请注意,LinkedHashSet不允许重复,因为它是一个集合。
搜索元素是否存在将使用contains()

为O(1)

使用LinkedHashSet还可以跟踪元素的添加位置,并按插入顺序进行迭代。

答案 1 :(得分:1)

如何使用hashmap

我会为密钥创建一个小类:

class Key {
  String dev, instr;

  // todo: implements equals & hashCode
}

并创建地图:

Map<Key, PanelData> map = new HashMap...

然后您可以通过调用map.get(new Key(...))轻松找到所需的元素。

您可以调整PanelData类,而不是创建一个新类,实现方法等于&amp; hashcode,以便当devinstr相等时,两个类是相等的。在这种情况下,您的地图将变为:

Map<PanelData, PanelData> map ...

// to add:
map.put(temps, temps)

// to search:
PanelData elem = map.get(new PanelData(desiredDev, desiredInstr));

答案 2 :(得分:1)

这里有一些优化。

1)重复使用call:panelArray.get(i)。在循环之外声明一个PanelData变量,但在循环开始时只初始化一次:

PanelData pd = null;
for (int i = 0; i < panelArray.size(); ++i) {
    pd = panelArray.get(i);

    ...
}

2)如果您的数据集允许,请考虑使用一些地图来帮助加快查找速度:

HashMap<String, PanelData> devToPanelDataMapping = new HashMap<String,PanelData>();
HashMap<String, PanelData> instToPanelDataMapping = new HashMap<String,PanelData>();

3)考虑将字符串散列为整数或长整数,因为String.equals()与(int == int)相比较慢

4)如果ArrayList只是只读,那么多线程解决方案可能会有所帮助。从文本文件中读取行的线程可以将各行数据分发给不同的“工作者”线程。

答案 3 :(得分:1)

1)首次创建PanelArray时,最大预期大小为+ 10%。 List<PanelData> panelArray = new ArrayList<PanelData>(130) - 这将阻止数组的动态重新分配,这将节省处理时间。

2)insert()做了什么?赔率是你的资源匮乏。

答案 4 :(得分:0)

使用HashMapSortedSet等不同的数据结构最有可能解决此问题。

为了使用HashMap,您需要定义一个可以为devinst字符串对生成哈希码的类。一种解决方案就像:

public class DevAndInstPair
{
    private String dev, inst;

    @Override
    public int hashCode() {
        return ((dev.hashCode() * 0x490aac18) ^ inst.hashCode());
    }

    @Override
    public boolean equals(Object o) {
        if (o == null || !(o instanceof DevAndInstPair)) {
            return false;
        }
        DevAndInstPair other = (DevAndInstPair) o;
        return (dev.equals(other.dev) && inst.equals(other.inst));
    }
}

然后,您可以使用HashMap<DevAndInstPair, PanelData>作为地图类型。

或者,如果您知道某个字符永远不会出现在dev字符串中,那么您可以将该字符用作将dev值与inst值分隔开的分隔符。假设此字符是连字符(' - '),键值为dest + '-' + inst,地图的键类型为String

要使用SortedSet,您可以PanelData实施Comparable<PanelData>或撰写实施Comparator<PanelData>的课程。请记住,比较操作必须与equals一致。

使用SortedSet比使用HashMap更棘手,但我个人认为这是解决此问题的更优雅方法。