列表过滤:从空列表重新创建,还是复制和删除元素?

时间:2011-05-30 13:23:24

标签: java arrays performance optimization arraylist

我有ArrayList,我需要对其进行过滤(仅限于删除某些元素)。

无法修改原始列表

关于表演的最佳选择是什么:

  • 重新创建原始列表中的其他列表,然后从中删除项目:

代码:

List<Foo> newList = new ArrayList<Foo>(initialList);
for (Foo item : initialList) {
    if (...) {
        newList.remove(item);
    }
}
  • 创建一个空列表,然后添加项目:

代码:

List<Foo> newList = new ArrayList<Foo>(initialList.size());
for (Foo item : initialList) {
    if (...) {
        newList.add(item);
    }
}

哪个选项最好?我应该使用除ArrayList之外的其他选项吗? (虽然我无法改变原始列表的类型)

作为附注,大约80%的项目将保留在列表中。该列表包含1到大约20个元素。

6 个答案:

答案 0 :(得分:2)

最好的选择是选择最容易编写和维护的内容。

如果性能有问题,您应该在之后对应用程序进行分析,而不是过早优化。

此外,我会使用像google-collections或commons集合这样的库进行过滤,以使代码更具可读性:

Collection<T> newCollection = Collections2.filter(new Predicate<T>() {
    public boolean apply(T item) {
        return (...); // apply your test here
    }
});

无论如何,因为看起来你正在优化性能,如果你确实要保留大部分原始项目,我会选择System.arraycopy

String[] arr = new String[initialList.size()];
String[] src = initialList.toArray(new String[initialList.size()]);
int dstIndex = 0, blockStartIdx=0, blockSize=0;
for (int currIdx=0; currIdx < initialList.size(); currIdx++) {
    String item = src[currIdx];
    if (item.length() <= 4) {
        if (blockSize > 0)
            System.arraycopy(src, blockStartIdx, arr, dstIndex, blockSize);
            dstIndex += blockSize;
            blockSize = 0;
        } else {
            if (blockSize == 0)
                blockStartIdx = currIdx;
            blockSize++;
        }
    }
    ArrayList newList = new ArrayList(arr.length + 1);
    newList.addAll(Arrays.asList(arr));
}

它似乎比你的选项快20%左右。如果你可以在最后跳过新的ArrayList创建,那么更是如此(40%)。

请参阅:http://pastebin.com/sDhV8BUL

答案 1 :(得分:1)

您可能希望从初始列表创建新列表并删除。由于你保留了大约80%的原始项目,因此它们会减少方法调用。

除此之外,我不知道有任何方法来过滤这些物品。

修改:显然Google Collections有something您可能会感兴趣吗?

答案 2 :(得分:1)

正如@Sanjay所说,“当有疑问时,衡量”。但是创建一个空的ArrayList然后向它添加项是最自然的实现,你的第一个目标应该是编写清晰易懂的代码。我99.9%肯定它也会更快。

更新:通过将旧列表复制到新列表然后删除不需要的元素,会产生元素删除的成本。 ArrayList.remove()方法需要在每次删除时迭代到数组的末尾,将每个引用复制到列表中的某个位置。这几乎肯定比仅仅创建一个新的ArrayList并向其添加元素更昂贵。

注意:确保将新的ArrayList分配给初始容量设置为旧List的大小,以避免重新分配成本。

答案 3 :(得分:0)

我首先遵循古老的建议;如果有疑问,请测量。

  

我应该使用除此之外的任何东西   ArrayList?

这取决于你将在筛选列表上执行什么样的操作,但ArrayList通常是一个不错的选择,除非你做的事情不应该由连续的列表支持元素(即数组)。

  

列出newList = new   的ArrayList(initialList.size());

我不是故意挑剔,但如果您的新列表不会超过初始大小的80%,为什么不将初始容量微调到((int)(initialList.size() * .8) + 1)

答案 4 :(得分:0)

第二个更快(迭代并根据需要添加到第二个),第一个代码将在删除任何项时抛出ConcurrentModificationException

并且就结果类型而言将取决于您将需要的

的过滤列表

答案 5 :(得分:0)

由于我只是在这里得到建议,所以我决定自己选择自己的工作台。

以下是结论(ArrayList的{​​{1}})。

  • 解决方案1,从副本中删除项目: 2400毫秒

  • 解决方案2,创建一个空列表并填写: 1600 ms String

  • 解决方案3,与2相同,只是您设置了列表的初始大小: 1530 ms newList = new ArrayList<Foo>();

  • 解决方案4,与2相同,只是您设置了List + 1的初始大小: 1500 ms newList = new ArrayList<Foo>(initialList.size());(由@Soronthar解释)

来源:http://pastebin.com/c2C5c9Ha