// ArrayList tourists
for (Tourist t : tourists) {
if (t != null) {
t.setId(idForm);
}
}
但这不是一个好的解决方案。有没有人可以提供更好的建议?
一些有用的基准测试,以做出更好的决策:
// ArrayList tourists
for (Tourist t : tourists) {
if (t != null) {
t.setId(idForm);
}
}
但这不是一个好的解决方案。有没有人可以提供更好的建议?
一些有用的基准测试,以做出更好的决策:
List.removeAll()
的时间复杂度为 n^2。就是这样。 - HemanthArrayList
和LinkedList
来说,它看起来都是 O(n)
。 - Helder PereiraN^2
并没有意义,因为两个集合的大小并不相关。最终复杂度应该是N*M
,但并非总是如此。ArrayList
覆盖了您链接的方法定义,以减少进行多次删除的开销,从而将其转换为N*T(c.contains)
;因此,如果参数c
中的集合是HashSet
,则它将是O(N)
;如果是TreeSet
,则它将是O(N*log M)
。同样的时间复杂度适用于LinkedList
,在那里他们不必付出太多努力,因为按定义删除很便宜(如果您有节点的引用)。 - Helder Pereira截至2015年,这是最佳方式(Java 8):
tourists.removeIf(Objects::isNull);
注意: 这段代码将会对固定大小的列表(如使用 Arrays.asList 创建的不可变列表)抛出 java.lang.UnsupportedOperationException
异常。
removeIf
会更快,但这只是我的猜测。 - MarcGlist.removeAll(Collections.singleton(null));
如果你在 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()]);
}
ImmutableList.copyOf(Iterables.filter(tourists, Predicates.notNull()))
虽不高效,但简短
while(tourists.remove(null));
for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
if (itr.next() == null) { itr.remove(); }
}
removeAll(..null..)
。谢谢! - MustafaObjects
类有一个nonNull
Predicate
,可以与filter
一起使用。tourists.stream().filter(Objects::nonNull).collect(Collectors.toList());
在Java 8之前,您应该使用:
tourists.removeAll(Collections.singleton(null));
Java 8之后的使用:
tourists.removeIf(Objects::isNull);
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();
}
}
从显式的角度来看,这是一个O(n)操作。
唯一可能更快的方法是从列表的两端迭代,并且当你发现一个空值时,将它的值设置为你在末尾找到的值,并将该值递减。然后迭代直到两个值匹配。你会混乱顺序,但相比于留下的值,你设置的值会大大减少。这是一个值得了解的好方法,但对于这里的情况并没有太大帮助,因为 .set() 基本上是免费的,然而,那种形式的删除是你工具箱中有用的工具。
for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
if (itr.next() == null) { itr.remove(); }
}
虽然这看起来足够合理,但迭代器上的 .remove() 在内部调用了:
ArrayList.this.remove(lastRet);
在remove操作中,其中再次出现O(n)的操作。它执行了System.arraycopy(),如果你关心速度,这不是你想要的。这使得它变成了n^2。
还有:
while(tourists.remove(null));
这个算法复杂度是O(m*n^2)。我们不仅仅是遍历列表,而是每次匹配到null时都要重新遍历整个列表。接下来我们需要进行n/2(平均)次System.arraycopy()操作来执行删除动作。
实际上,你可以在更短的时间内对所有有问题的项进行排序,将具有值的项与具有空值的项分开并在末尾进行修剪。至少在理论上来说,System.arraycopy()实际上并不是一个N操作。但理论和实践总是有差距的。
主要我在使用这个:
list.removeAll(Collections.singleton(null));
但是在学了Java 8之后,我转向使用以下语言:
List.removeIf(Objects::isNull);
stream()
和filter()
来实现此操作。tourists = tourists.stream().filter(t -> t != null).collect(Collectors.toList())
或者
tourists = tourists.stream().filter(Objects::nonNull).collect(Collectors.toList())
Iterator
吗?查看java-doc。http://download.oracle.com/javase/6/docs/api/java/util/Iterator.html#remove(&#8203;) - Nishant