Jua*_*ios 179 java performance loops for-loop arraylist
我试着用这样的循环
// ArrayList tourists
for (Tourist t : tourists) {
if (t != null) {
t.setId(idForm);
}
}
Run Code Online (Sandbox Code Playgroud)
但这并不好.谁能建议我一个更好的解决方案?
一些有用的基准可以做出更好的决策:
Lit*_*ium 355
尝试:
tourists.removeAll(Collections.singleton(null));
Run Code Online (Sandbox Code Playgroud)
阅读Java API.代码将抛出java.lang.UnsupportedOperationException
不可变列表(例如创建的Arrays.asList
); 有关详细信息,请参阅此答案.
Mar*_*rcG 111
截至2015年,这是最好的方式(Java 8):
tourists.removeIf(Objects::isNull);
Run Code Online (Sandbox Code Playgroud)
注意:此代码将抛出java.lang.UnsupportedOperationException
固定大小的列表(例如使用Arrays.asList创建),包括不可变列表.
AZ_*_*AZ_ 46
list.removeAll(Collections.singleton(null));
Run Code Online (Sandbox Code Playgroud)
如果在Arrays.asList上使用它,它将抛出UnsupportedException,因为它为您提供了Immutable副本,因此无法修改它.见下面的代码.它创建Mutable副本,不会抛出任何异常.
public static String[] clean(final String[] v) {
List<String> list = new ArrayList<String>(Arrays.asList(v));
list.removeAll(Collections.singleton(null));
return list.toArray(new String[list.size()]);
}
Run Code Online (Sandbox Code Playgroud)
Pet*_*rey 18
效率不高,但很短
while(tourists.remove(null));
Run Code Online (Sandbox Code Playgroud)
小智 18
如果您更喜欢不可变数据对象,或者您不想破坏输入列表,则可以使用Guava的谓词.
ImmutableList.copyOf(Iterables.filter(tourists, Predicates.notNull()))
Run Code Online (Sandbox Code Playgroud)
for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
if (itr.next() == null) { itr.remove(); }
}
Run Code Online (Sandbox Code Playgroud)
小智 5
该类Objects
有一个nonNull
Predicate
可以与 一起使用的filter
。
例如:
tourists.stream().filter(Objects::nonNull).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
您应该使用 Java 8 之前的版本:
tourists.removeAll(Collections.singleton(null));
Run Code Online (Sandbox Code Playgroud)
后 Java 8 使用:
tourists.removeIf(Objects::isNull);
Run Code Online (Sandbox Code Playgroud)
这里的原因是时间复杂度。数组的问题是删除操作可能需要 O(n) 时间才能完成。实际上,在 Java 中,这是剩余元素的数组副本,用于替换空白位置。此处提供的许多其他解决方案将触发此问题。前者在技术上是 O(n*m),其中 m 是 1,因为它是一个单例 null:所以 O(n)
您应该删除所有的单例,它在内部执行一个具有读取位置和写入位置的 batchRemove()。并迭代列表。当它遇到一个空值时,它只是将读取位置迭代 1。当它们相同时它通过,当它们不同时它继续复制值。然后在最后它修剪到大小。
它在内部有效地做到了这一点:
public static <E> void removeNulls(ArrayList<E> list) {
int size = list.size();
int read = 0;
int write = 0;
for (; read < size; read++) {
E element = list.get(read);
if (element == null) continue;
if (read != write) list.set(write, element);
write++;
}
if (write != size) {
list.subList(write, size).clear();
}
}
Run Code Online (Sandbox Code Playgroud)
您可以明确看到是 O(n) 操作。
唯一可能更快的是,如果您从两端迭代列表,当您找到一个空值时,您将它的值设置为您在最后找到的值,然后递减该值。并迭代直到两个值匹配。您会弄乱顺序,但会大大减少您设置的值与您单独留下的值的数量。这是一个很好的了解方法,但在这里没有多大帮助,因为 .set() 基本上是免费的,但这种删除形式对您的腰带来说是一个有用的工具。
for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
if (itr.next() == null) { itr.remove(); }
}
Run Code Online (Sandbox Code Playgroud)
虽然这看起来很合理,但迭代器上的 .remove() 内部调用:
ArrayList.this.remove(lastRet);
Run Code Online (Sandbox Code Playgroud)
这又是移除中的 O(n) 操作。如果您关心速度,它会执行 System.arraycopy() 这又不是您想要的。这使它成为 n^2。
还有:
while(tourists.remove(null));
Run Code Online (Sandbox Code Playgroud)
这是 O(m*n^2)。这里我们不仅迭代列表。每次我们匹配空值时,我们都会重申整个列表。然后我们执行 n/2(平均)操作来执行 System.arraycopy() 以执行删除。从字面上看,您可以在具有值的项目和具有空值的项目之间对整个集合进行排序,并在更短的时间内修剪结尾。事实上,对于所有破碎的人来说都是如此。至少在理论上,实际的 system.arraycopy 实际上并不是一个 N 操作。理论上,理论和实践是一回事;实际上他们不是。
我主要用的是这个:
list.removeAll(Collections.singleton(null));
Run Code Online (Sandbox Code Playgroud)
但在我学习了 Java 8 之后,我改用了这个:
List.removeIf(Objects::isNull);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
176921 次 |
最近记录: |