在for循环中重新创建ArrayList的最快方法

Sop*_*ner 6 java arraylist clear

在Java中,使用以下函数为巨大的矩阵X打印其列不同的元素:

// create the list of distinct values
List<Integer> values = new ArrayList<Integer>();

// X is n * m int[][] matrix
for (int j = 0, x; j < m; j++) {
    values.clear();
    for (int i = 0; i < n; i++) {
        x = X[i][j];
        if (values.contains(x)) continue;
        System.out.println(x);
        values.add(x);
    }
}
Run Code Online (Sandbox Code Playgroud)

首先,我按列(索引j)和内部按行(索引i)进行迭代.

对于不同的矩阵,此函数将被调用数百万次,因此应优化代码以满足性能要求.我想知道值数组.使用values = new ArrayList<Integer>();values = null替代它会更快values.clear()吗?

ass*_*ias 16

更有效的是使用Set而不是列表,例如HashSet实现.contains方法将在O(1)而不是O(n)中运行,并带有一个列表.您只需调用add方法即可保存一个调用.

至于你的具体问题,我只想在每个循环中创建一个新的Set - 对象创建并不昂贵,可能不如清除集合(由底部的基准测试确认 - 请参阅编辑2中最有效的版本):

for (int j = 0, x; j < m; j++) {
    Set<Integer> values = new HashSet<Integer>();
    for (int i = 0; i < n; i++) {
        x = X[i][j];
        if (!values.add(x)) continue; //value.add returns true if the element was NOT in the set before
        System.out.println(x);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,知道哪个更快(新对象与清除)的唯一方法是分析代码的这一部分并检查两个版本的性能.

编辑

我运行了一个快速基准测试,清晰版本看起来比在每个循环中创建一个集合要快一些(约20%).您仍然应该检查您的数据集/用例哪个更好.使用我的数据集加快代码:

Set<Integer> values = new HashSet<Integer>();
for (int j = 0, x; j < m; j++) {
    for (int i = 0; i < n; i++) {
        x = X[i][j];
        if (!values.add(x)) continue; //value.add returns true if the element was NOT in the set before
        System.out.println(x);
    }
    values.clear();
}
Run Code Online (Sandbox Code Playgroud)

编辑2

通过在每个循环中创建一个正确大小的新集合,可以获得更快的代码版本:

for (int j = 0, x; j < m; j++) {
    Set<Integer> values = new HashSet<Integer>(n, 1); //right size from the beginning
    for (int i = 0; i < n; i++) {
        x = X[i][j];
        if (!values.add(x)) continue; //value.add returns true if the element was NOT in the set before
        System.out.println(x);
    }
}
Run Code Online (Sandbox Code Playgroud)

结果摘要

在JVM热身+ JIT之后:

Set<Integer> values = new HashSet<Integer>(n, 1); =====> 280 ms
values.clear();                                   =====> 380 ms
Set<Integer> values = new HashSet<Integer>();     =====> 450 ms 
Run Code Online (Sandbox Code Playgroud)

  • @aromero"O(1)"和"常数时间"绝对*做*意思相同; 随意链接到另有说明的参考.虽然我同意这是最好的情况,并且Javadoc说的很多,只要整数没有按排序顺序到达,事情就会正常工作. (7认同)
  • @aromero - 确定无疑.来自Javadocs的引用:"这个类为基本操作提供恒定的时间性能(添加,删除,包含和大小)......" (2认同)
  • @ cl-r完全没有任何意义,在任何这个代码中都没有任何人循环遍历列表*或*一组. (2认同)
  • @aromero你说的是事实错误.如果您能找到参考,请随意分享参考. (2认同)