ArrayListまたはString配列からすべてのnull要素を削除する方法は?


187

そんなループでやってみます

// ArrayList tourists

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

しかし、それは良くありません。誰かが私にもっと良い解決策を提案できますか?


より適切な決定を行うためのいくつかの有用なベンチマーク:

Whileループ、Forループ、イテレータパフォーマンステスト


2
使用しIteratorますか?java-docを掘る。download.oracle.com/javase/6/docs/api/java/util/...
Nishant

回答:


365

試してください:

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

Java APIをお読みください。コードはjava.lang.UnsupportedOperationException不変のリスト(で作成されたものなどArrays.asList)をスローします。詳細については、この回答を参照してください。


9
の時間の複雑さList.removeAll()n ^ 2です。ただ言って。
Hemanth 2016

8
Java 8以降については、以下の@MarcGの回答を参照してください。
アンディトーマス

2
@Hemanthどのようにしてその時間の複雑さを実現したかについて詳しく説明できますか?O(n)との両方ArrayListで私にはかなり見えますLinkedList
Helder Pereira

1
@HelderPereira ソース(349行目)は両方のリストをループする(配列全体をループする)ようであり、は要素が1つしかないため、このケースに当てはまるとは思いません。しかし、一般的にはそうなります。contains()singletonN * 1 = NN^2
モイラ2017年

6
@Hemanthいいえ、そうではありません。これはn * mで、mは要素の数です。この場合、nullのシングルトンは1です。O(n)です。ここでソースコードを確認し、リストを一度に読み書きして、削除された要素を説明するために要素を移動することがわかります。
酒石化

116

2015年現在、これが最良の方法です(Java 8)。

tourists.removeIf(Objects::isNull);

注:このコードはjava.lang.UnsupportedOperationException、不変リストを含む固定サイズのリスト(Arrays.asListで作成されたものなど)に対してスローされます。


1
どのように「最高」ですか?他のアプローチよりも速いですか?それとも、簡潔さのおかげでもっと読みやすいですか?
アンディトーマス

15
簡潔さのためだけでなく、より表現力があるためです。「観光客から、オブジェクトがnullの場合は削除する」とほぼ読めます。また、古い方法では、1つのnullオブジェクトを使用して新しいコレクションを作成し、コレクションのコンテンツを他のオブジェクトから削除するように求めていました。ちょっとハックのようですよね?速度に関しては、ポイントがあります。リストが本当に大きく、パフォーマンスが懸念される場合は、両方の方法をテストすることをお勧めします。私の推測ではそれremoveIfはより高速ですが、それは推測です。
MarcG 2016

1
Arrays.asList不変ではありません。固定サイズです。
ターバノフ2016

@turbanoffはい、もちろんそうです。固定サイズのみなので、回答を更新します。
MarcG

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

それは意志例外UnsupportedExceptionを、それはあなたを与えるので、あなたはは、Arrays.asListにそれを使用する場合は不変、それを修正することはできませんので、コピーを。コードの下を参照してください。可変コピーを作成し、例外をスローしません。

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

18

効率的ではないが短い

while(tourists.remove(null));

1
残念ながら、あなたの解決策は私のために働いた唯一のものでした...ありがとう!
Pkmmte 2014年

シンプルで高速

5
@mimraheは実際には高速の反対です。あなたが大きなリストを持っている場合はひどく遅い。
Gewure 2017

18

不変データオブジェクトを使用する場合、または入力リストを破壊したくない場合は、Guavaの述語を使用できます。

ImmutableList.copyOf(Iterables.filter(tourists, Predicates.notNull()))

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

これは、トラバース中に要素を削除する必要がある場合により便利です。偶然は、私が使用しようとするよりも要素を無効にしていたことremoveAll(..null..)です。ありがとう!
Mustafa

値をnullに設定してから、最後に削除する方がよい場合があります。removeAllのbatchRemoveは、読み取りと書き込みの場所を使用してリストを横断し、リストを1回反復し、nullに達したときに読み取りを移動しますが、書き込みは移動しません。.remove()呼び出されるたびに配列全体をarraycopyする必要がある場合があります。
酒石化

4

使用する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)操作です。

これまでより速くなる可能性がある唯一のことは、リストを両端から繰り返し、nullを見つけたときに、その値を最後に見つけた値と等しく設定し、その値をデクリメントすることです。そして、2つの値が一致するまで繰り返しました。順序をめちゃくちゃにしてしまいますが、設定した値の数をそのままにしておくよりも大幅に減らすことができます。これは知っておくと良い方法ですが、ここでは.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)です。ここでは、リストを反復するだけではありません。nullに一致するたびに、リスト全体を繰り返します。次に、n。2(平均)操作を実行して、System.arraycopy()を実行して削除を実行します。文字通り、値を持つアイテムとnull値を持つアイテムの間でコレクション全体を並べ替え、短い時間で終了をトリミングできます。実際、それは壊れたものすべてに当てはまります。少なくとも理論的には、実際のsystem.arraycopyは実際にはN演算ではありません。理論的には、理論と実践は同じものです。実際にはそうではありません。


3

nullからすべての値を削除する簡単な方法がありますcollection。nullを含むコレクションをパラメータとしてremoveAll()メソッドに渡す必要があります。

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

yourCollection.removeAll(s1);

これは私にとって最も効果的でした。また、元のコレクションのremoveAllメソッドに渡される「フィルター配列」に複数のエントリを簡単に追加することもできます。

3

Objectsクラスが持っているnonNull Predicateと一緒に使用することができるがfilter

例えば:

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

1
Stack Overflowへようこそ。質問に答えるときは、コードの説明を追加してください。戻って回答を編集し、詳細情報を含めてください。
タイラー

3

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-ストリーム


1
このソリューションは不変のコピーで機能します。つまり、-> List <String> listOfString = Arrays.asList( "test1"、null、 "test"); .....も!ありがとう
Anurag_BEHS

2

これは、arraylistからデフォルトのnull値を削除する簡単な方法です

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

それ以外の場合、文字列値「null」はarraylistから削除されます

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

1

これをいじってみたところ、trimToSize()が機能しているようです。私はAndroidプラットフォームで作業しているため、異なる場合があります。


2
javadocによると、trimToSizeの内容は変更されませんArrayList。これがアンドロイドで異なる場合、それはおそらくバグです。
ファビアン2016年

1

同じようにイテレータを使用して、すべてのnull値を削除できます。

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

1

新しいリストを生成するために、ストリームインターフェイスをストリーム操作のcollectおよびヘルパーメソッドと一緒に使用しました。

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

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

2
tourists.stream().filter(s -> s != null).collect(Collectors.toList());
1ac0 2016

1

主に私はこれを使用しています:

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

しかし、Java 8を学んだ後、私はこれに切り替えました:

List.removeIf(Objects::isNull);

0

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]

並列ストリームは、利用可能なプロセッサを利用し、適切なサイズのリストのプロセスを高速化します。ストリームを使用する前にベンチマークすることを常にお勧めします。


0

@Lithiumの回答に似ていますが、「リストにタイプnullが含まれていない可能性があります」エラーはスローされません。

   list.removeAll(Collections.<T>singleton(null));

0
List<String> colors = new ArrayList<>(
Arrays.asList("RED", null, "BLUE", null, "GREEN"));
// using removeIf() + Objects.isNull()
colors.removeIf(Objects::isNull);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.