簡體   English   中英

如何從 ArrayList 或 String Array 中刪除所有空元素?

[英]How to remove all null elements from a ArrayList or String Array?

我嘗試使用這樣的循環

// ArrayList tourists

for (Tourist t : tourists) {
    if (t != null) {     
        t.setId(idForm); 
    }   
}

但這並不好。 誰能建議我一個更好的解決方案?


一些有用的基准可以做出更好的決策:

While 循環、For 循環和迭代器性能測試

嘗試:

tourists.removeAll(Collections.singleton(null));

閱讀Java API 對於不可變列表(例如使用Arrays.asList創建),代碼將拋出java.lang.UnsupportedOperationException 有關更多詳細信息,請參閱此答案

截至 2015 年,這是最好的方法(Java 8):

tourists.removeIf(Objects::isNull);

注意:對於固定大小的列表(例如使用 Arrays.asList 創建),包括不可變列表,此代碼將拋出java.lang.UnsupportedOperationException

list.removeAll(Collections.singleton(null));

如果你在 Arrays.asList 上使用它,它會拋出UnsupportedException因為它給你不可變的副本所以它不能被修改。 請參閱下面的代碼。 它創建可變副本並且不會拋出任何異常。

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()]);
}

效率不高,但很短

while(tourists.remove(null));

如果您更喜歡不可變數據對象,或者您只是不想破壞輸入列表,則可以使用 Guava 的謂詞。

ImmutableList.copyOf(Iterables.filter(tourists, Predicates.notNull()))
 for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
      if (itr.next() == null) { itr.remove(); }
 }

您應該使用 Java 8 之前的版本:

tourists.removeAll(Collections.singleton(null));

后 Java 8 使用:

tourists.removeIf(Objects::isNull);

這里的原因是時間復雜度。 數組的問題是刪除操作可能需要 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();
    }
}

您可以明確看到是 O(n) 操作。

唯一可能更快的是,如果您從兩端迭代列表,當您找到一個空值時,您將它的值設置為您在最后找到的值,然后遞減該值。 並迭代直到兩個值匹配。 您會弄亂順序,但會大大減少您設置的值與您單獨留下的值的數量。 這是一個很好的了解方法,但在這里沒有多大幫助,因為 .set() 基本上是免費的,但這種刪除形式對您的腰帶來說是一個有用的工具。


for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
      if (itr.next() == null) { itr.remove(); }
 }

雖然這看起來很合理,但迭代器上的 .remove() 內部調用:

ArrayList.this.remove(lastRet);

這又是移除中的 O(n) 操作。 如果您關心速度,它會執行 System.arraycopy() 這又不是您想要的。 這使它成為 n^2。

還有:

while(tourists.remove(null));

這是 O(m*n^2)。 這里我們不僅迭代列表。 每次我們匹配空值時,我們都會重申整個列表。 然后我們執行 n/2(平均)操作來執行 System.arraycopy() 以執行刪除。 從字面上看,您可以在具有值的項目和具有空值的項目之間對整個集合進行排序,並在更短的時間內修剪結尾。 事實上,對於所有破碎的人來說都是如此。 至少在理論上,實際的 system.arraycopy 實際上並不是一個 N 操作。 理論上,理論和實踐是一回事; 實際上他們不是。

使用 Java 8,您可以使用stream()filter()

tourists = tourists.stream().filter(t -> t != null).collect(Collectors.toList())

tourists = tourists.stream().filter(Objects::nonNull).collect(Collectors.toList())

有關更多信息: Java 8 - 流

Objects類具有可與filter一起使用的nonNull Predicate

例如:

tourists.stream().filter(Objects::nonNull).collect(Collectors.toList());

我主要是用這個:

list.removeAll(Collections.singleton(null));

但是在我學習了 Java 8 之后,我轉向了這個:

List.removeIf(Objects::isNull);

有一種簡單的方法可以從collection中刪除所有null值。您必須將包含空值的集合作為參數傳遞給removeAll()方法

List s1=new ArrayList();
s1.add(null);

yourCollection.removeAll(s1);

這是從數組列表中刪除默認空值的簡單方法

     tourists.removeAll(Arrays.asList(null));  

否則字符串值“null”從數組列表中刪除

       tourists.removeAll(Arrays.asList("null"));  

我們可以使用迭代器來刪除所有空值。

Iterator<Tourist> itr= tourists.iterator();
while(itr.hasNext()){
    if(itr.next() == null){
        itr.remove();
    }
}

我將流接口與流操作collect和輔助方法一起使用來生成新列表。

tourists.stream().filter(this::isNotNull).collect(Collectors.toList());

private <T> boolean isNotNull(final T item) {
    return  item != null;
}

我玩弄了這個,發現 trimToSize() 似乎有效。 我在 Android 平台上工作,所以它可能會有所不同。

使用Java 8,可以使用流、並行流和removeIf方法以各種方式執行此操作:

List<String> stringList = new ArrayList<>(Arrays.asList(null, "A", "B", null, "C", null));
List<String> listWithoutNulls1 = stringList.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList()); //[A,B,C]
List<String> listWithoutNulls2 = stringList.parallelStream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList()); //[A,B,C]
stringList.removeIf(Objects::isNull); //[A,B,C]

並行流將利用可用的處理器,並將加速合理大小列表的過程。 始終建議在使用流之前進行基准測試。

類似於@Lithium 答案,但不會拋出“列表可能不包含空類型”錯誤:

   list.removeAll(Collections.<T>singleton(null));
List<String> colors = new ArrayList<>(
Arrays.asList("RED", null, "BLUE", null, "GREEN"));
// using removeIf() + Objects.isNull()
colors.removeIf(Objects::isNull);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM