当前位置: 首页 > 面试题库 >

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

萧鹏云
2023-03-14
问题内容

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

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

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


问题答案:

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

至于您的特定问题,我将在每个循环处创建一个新的Set-对象创建并没有那么昂贵,可能比清除该set少(如底部的基准所确认-请参见EDIT 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);
    }
}

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

编辑

我运行了一个快速基准测试,清晰的版本似乎比在每个循环上创建一个集合要快一些(大约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();
}

编辑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);
    }
}

结果汇总

JVM预热+ JIT之后:

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


 类似资料:
  • 问题内容: 我有一个包含以下代码段的受测试方法: 我的单元测试代码如下所示: 问题是,在运行测试时,测试代码永远不会进入for循环。我应该在什么时候指定条件才能进入for循环?目前,我已指定,但我猜它从未使用过。 问题答案: 您的问题是,在for-each循环中使用集合时,将调用其方法;而且您还没有使用该特定方法。 我强烈建议您传递一个真实的列表,而不是模拟列表,该列表中的元素只是您的模拟对象,您

  • 我试图研究我的数据中有零值的概率,我开发了一个代码,当一列数据为零时输出另一列数据的值,这正是我所需要的。但是,对于577BY29数据流中的每一列和其他28列都要这样做是很困难的,所以我决定创建一个for循环,在我有以下内容的地方为我这样做: 您可以看到,当输出数据帧有n=29列时,代码循环正确,但对于上面指定的条件,代码循环不正确。 请帮忙,谢谢!

  • 我对编程有点陌生,我被卡住了。假设我在一个项目中有五个不同的类:foo1、foo2、foo3、foo4和foo5,它们都做不同但相似的事情。现在假设我需要为每个对象创建一个新对象,比如:foo1 bar1=new foo1();foo2 bar2=新的foo2();foo3 bar3=新的foo3();等等当然这是可行的,但如果我能在一个for循环中实例化我需要的所有对象,或者至少把我想要创建的所

  • 创建新的Arraylist(如第一种方法)与创建第二种方法之间的区别是什么?在创建一个时,您考虑了什么?

  • 在我的很多代码中,我做了如下操作: 快速返回一个新数组,其中只包含我需要的已处理数据。但是,在其当前形式中,如果不返回任何内容,新数组将有一个

  • 我当前正在将一个ArrayList转换为一个字符串,以便将其发送到一个DB,这样我就可以在另一端检索它,并稍后将其转换回一个ArrayList。 我的思路是通过执行以下操作将其转换为当前的字符串 是ArrayList,看起来如下所示: 当我查看数据库时,它看起来像这样 如何删除开头的和最后的以便在数据库上看起来像? 在另一端,我可以使用以下方法获得它: (我正在使用SQLite,这是我大学项目的一