n個のオブジェクトの配列が与えられ、それが文字列の配列であり、次の値を持っているとしましょう。
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
配列内の「a」に等しいすべての文字列/オブジェクトを削除/削除するにはどうすればよいですか?
n個のオブジェクトの配列が与えられ、それが文字列の配列であり、次の値を持っているとしましょう。
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
配列内の「a」に等しいすべての文字列/オブジェクトを削除/削除するにはどうすればよいですか?
回答:
[すぐに使用できるコードが必要な場合は、(カット後の)私の「Edit3」までスクロールしてください。残りは後世のためにここにあります。]
肉付けするにDustmanのアイデアを:
List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);
編集:私は現在、Arrays.asList
代わりに使用していますCollections.singleton
:シングルトンは1つのエントリに制限されていasList
ますが、このアプローチでは、後で除外するために他の文字列を追加できます:Arrays.asList("a", "b", "c")
。
Edit2:上記のアプローチは同じ配列を保持します(したがって、配列は同じ長さのままです)。最後の後の要素はnullに設定されます。あなたがしたい場合は、新しい配列が正確に要求されるようなサイズ、これを代わりに使用します。
array = list.toArray(new String[0]);
Edit3:同じクラスでこのコードを頻繁に使用する場合は、これをクラスに追加することを検討してください。
private static final String[] EMPTY_STRING_ARRAY = new String[0];
次に、関数は次のようになります。
List<String> list = new ArrayList<>();
Collections.addAll(list, array);
list.removeAll(Arrays.asList("a"));
array = list.toArray(EMPTY_STRING_ARRAY);
これによりnew
、関数が呼び出されるたびに編集される、役に立たない空の文字列配列がヒープに散らばるのを防ぐことができます。
cynicalmanの提案(コメントを参照)もヒープのポイ捨てに役立ちます。公平を期すために、次のように言及する必要があります。
array = list.toArray(new String[list.size()]);
明示的なサイズを間違える方が簡単な場合があるため(たとえば、size()
間違ったリストを呼び出す)、私のアプローチを好みます。
Java 8の代替手段:
String[] filteredArray = Arrays.stream(array)
.filter(e -> !e.equals(foo)).toArray(String[]::new);
Stream.of(foo).filter(s -> ! s.equals("a")).toArray()
十分でしょう。
を使用しList
て配列を作成しArrays.asList()
、remove()
適切なすべての要素を呼び出します。次にtoArray()
、「リスト」を呼び出して、再び配列に戻します。
それほどパフォーマンスは良くありませんが、適切にカプセル化すれば、後でいつでもより迅速に何かを行うことができます。
Arrays.asList()
はをサポートしていないと指摘しましたremove()
。それで、この答えは完全に無効ですか?一部のコメントが削除されたようですので、これが議論されたかどうかはわかりません。
あなたはいつでもすることができます:
int i, j;
for (i = j = 0; j < foo.length; ++j)
if (!"a".equals(foo[j])) foo[i++] = foo[j];
foo = Arrays.copyOf(foo, i);
外部ライブラリを使用できます。
org.apache.commons.lang.ArrayUtils.remove(java.lang.Object[] array, int index)
これはプロジェクトApacheCommons Langhttp://commons.apache.org/lang/にあります。
ArrayUtils.removeElement(boolean[] array, boolean element)
また、非常に便利です。
配列に変換しList
たり、追加の配列を作成したりせずに配列から複数の要素を削除する必要がある場合は、削除するアイテムの数に依存せずにO(n)で行うことができます。
ここで、a
は初期配列であり、int... r
削除する要素の個別の順序付けられたインデックス(位置)です。
public int removeItems(Object[] a, int... r) {
int shift = 0;
for (int i = 0; i < a.length; i++) {
if (shift < r.length && i == r[shift]) // i-th item needs to be removed
shift++; // increment `shift`
else
a[i - shift] = a[i]; // move i-th item `shift` positions left
}
for (int i = a.length - shift; i < a.length; i++)
a[i] = null; // replace remaining items by nulls
return a.length - shift; // return new "length"
}
小規模なテスト:
String[] a = {"0", "1", "2", "3", "4"};
removeItems(a, 0, 3, 4); // remove 0-th, 3-rd and 4-th items
System.out.println(Arrays.asList(a)); // [1, 2, null, null, null]
タスクでは、最初に配列をスキャンして「a」の位置を収集してから、を呼び出すことができますremoveItems()
。
ここにはたくさんの答えがあります-私が見ている問題は、コレクションの代わりに配列を使用している理由を言わなかったということですので、いくつかの理由とどの解決策が適用されるかを提案させてください(ほとんどの解決策ここでは他の質問ですでに回答されているので、あまり詳しくは説明しません):
理由:コレクションパッケージが存在することを知らなかったか、信頼していませんでした
解決策:コレクションを使用します。
途中から追加/削除する場合は、LinkedListを使用してください。サイズが本当に心配な場合、またはコレクションの真ん中にインデックスを付けることが多い場合は、ArrayListを使用してください。これらの両方に削除操作が必要です。
理由:サイズが心配であるか、メモリ割り当てを制御したい
解決策:特定の初期サイズのArrayListを使用します。
ArrayListは、それ自体を展開できる単なる配列ですが、必ずしもそうする必要はありません。アイテムの追加/削除については非常に賢明ですが、LOTを途中から挿入/削除する場合は、LinkedListを使用してください。
理由:配列が入ってくる配列と出て行く配列があるので、配列を操作したい
解決策:それをArrayListに変換し、アイテムを削除してから元に戻します
理由:自分でやればもっと良いコードを書けると思う
解決策:配列またはリンクリストを使用することはできません。
理由:これはクラスの割り当てであり、許可されていないか、何らかの理由でコレクションAPIにアクセスできません
仮定:新しい配列は正しい「サイズ」である必要があります
解決策:配列をスキャンして一致するアイテムを探し、それらをカウントします。正しいサイズの新しい配列を作成します(元のサイズ-一致数)。System.arraycopyを繰り返し使用して、保持するアイテムの各グループを新しい配列にコピーします。これがクラス割り当てであり、System.arraycopyを使用できない場合は、ループ内で一度に1つずつ手動でコピーしますが、本番コードでは非常に遅いため、これを行わないでください。(これらの解決策は両方とも他の回答で詳しく説明されています)
理由:ベアメタルを実行する必要があります
前提:不必要にスペースを割り当てたり、時間がかかりすぎたりしてはいけません
前提:削除/挿入のために配列を再割り当てする必要があるため、配列で使用されるサイズ(長さ)を個別に追跡しています。
これを実行する理由の例:プリミティブの単一配列(int値としましょう)は、RAMのかなりの部分(50%など)を使用しています。ArrayListは、これらを、その数倍のメモリを使用するIntegerオブジェクトへのポインタのリストに強制します。
解決策:配列を繰り返し処理し、削除する要素を見つけたら(それを要素nと呼びましょう)、System.arraycopyを使用して、配列の末尾を「削除された」要素にコピーします(ソースと宛先は同じ配列です)。メモリがそれ自体を上書きしないように正しい方向にコピーを行うのに十分賢いです:
System.arraycopy(ary、n + 1、ary、n、length-n) 長さ-;
一度に複数の要素を削除する場合は、おそらくこれよりも賢くなりたいと思うでしょう。テール全体ではなく、1つの「一致」と次の「一致」の間の領域のみを移動し、いつものように、チャンクを2回移動することは避けます。
この最後のケースでは、絶対に自分で作業を行う必要があります。System.arraycopyを使用することが、コンピュータアーキテクチャのメモリを移動するための最良の方法を選択するため、実際に行う唯一の方法です。これは、何倍も高速である必要があります。あなたが合理的に自分で書くことができるどんなコードよりも。
それのリストを作成してから削除してから配列に戻すことについての何かが私を間違っていると思います。テストはしていませんが、以下の方がパフォーマンスが良いと思います。はい、私はおそらく過度に事前最適化しています。
boolean [] deleteItem = new boolean[arr.length];
int size=0;
for(int i=0;i<arr.length;i==){
if(arr[i].equals("a")){
deleteItem[i]=true;
}
else{
deleteItem[i]=false;
size++;
}
}
String[] newArr=new String[size];
int index=0;
for(int i=0;i<arr.length;i++){
if(!deleteItem[i]){
newArr[index++]=arr[i];
}
}
これは非常に古い投稿だと思いますが、ここでの回答のいくつかは私を助けてくれたので、これが私のタペンスです 'ha'ペニーの価値があります!
ArrayList
リストのサイズを変更しない限り、書き戻している配列のサイズを変更する必要があることを確認する前に、これを機能させるのにかなり苦労しました。
場合ArrayList
あなたがアップし、それはで起動よりも大きいか少ない要素で終わるを変更していることを、ラインはList.toArray()
あなたのような何かを必要とするので、例外が発生しますList.toArray(new String[] {})
か、List.toArray(new String[0])
新しい(正しい)サイズの配列を作成するために。
私がそれを知った今、明白に聞こえます。新しくてなじみのないコード構造に慣れてきたAndroid / Javaの初心者にはそれほど明白ではなく、ここでの以前の投稿のいくつかからは明らかではないので、私のように何時間も頭を悩ませている他の人にとってこの点を本当に明確にしたかっただけです!!
編集:
配列内のヌルのあるポイントがクリアされました。コメントしてすみません。
元の:
えーと...ライン
array = list.toArray(array);
削除された要素がnullであった配列内のすべてのギャップを置き換えます。要素が削除されるため、これは危険な場合がありますが、配列の長さは同じままです。
これを回避したい場合は、toArray()のパラメーターとして新しい配列を使用してください。removeAllを使用したくない場合は、Setが代わりになります。
String[] array = new String[] { "a", "bc" ,"dc" ,"a", "ef" };
System.out.println(Arrays.toString(array));
Set<String> asSet = new HashSet<String>(Arrays.asList(array));
asSet.remove("a");
array = asSet.toArray(new String[] {});
System.out.println(Arrays.toString(array));
与える:
[a, bc, dc, a, ef]
[dc, ef, bc]
Chris Yester Youngからの現在受け入れられている回答は、次のように出力されます。
[a, bc, dc, a, ef]
[bc, dc, ef, null, ef]
コードで
String[] array = new String[] { "a", "bc" ,"dc" ,"a", "ef" };
System.out.println(Arrays.toString(array));
List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);
System.out.println(Arrays.toString(array));
null値を残さずに。
この問題への私の小さな貢献。
public class DeleteElementFromArray {
public static String foo[] = {"a","cc","a","dd"};
public static String search = "a";
public static void main(String[] args) {
long stop = 0;
long time = 0;
long start = 0;
System.out.println("Searched value in Array is: "+search);
System.out.println("foo length before is: "+foo.length);
for(int i=0;i<foo.length;i++){ System.out.println("foo["+i+"] = "+foo[i]);}
System.out.println("==============================================================");
start = System.nanoTime();
foo = removeElementfromArray(search, foo);
stop = System.nanoTime();
time = stop - start;
System.out.println("Equal search took in nano seconds = "+time);
System.out.println("==========================================================");
for(int i=0;i<foo.length;i++){ System.out.println("foo["+i+"] = "+foo[i]);}
}
public static String[] removeElementfromArray( String toSearchfor, String arr[] ){
int i = 0;
int t = 0;
String tmp1[] = new String[arr.length];
for(;i<arr.length;i++){
if(arr[i] == toSearchfor){
i++;
}
tmp1[t] = arr[i];
t++;
}
String tmp2[] = new String[arr.length-t];
System.arraycopy(tmp1, 0, tmp2, 0, tmp2.length);
arr = tmp2; tmp1 = null; tmp2 = null;
return arr;
}
}
それはあなたが「取り除く」という意味に依存しますか?配列は固定サイズの構造であり、その中の要素の数を変更することはできません。したがって、a)不要な要素を含まない新しい短い配列を作成するか、b)不要なエントリを「空」ステータスを示すものに割り当てることができます。プリミティブを使用していない場合、通常はnullです。
最初のケースでは、配列からリストを作成し、要素を削除して、リストから新しい配列を作成します。パフォーマンスが重要な場合は、削除してはならない要素をリストに割り当てて配列を繰り返し処理し、リストから新しい配列を作成します。2番目のケースでは、単純に調べて、配列エントリにnullを割り当てます。
ああ、コードを正しく表示できません。申し訳ありませんが、動作しました。申し訳ありませんが、質問を正しく読んでいないと思います。
String foo[] = {"a","cc","a","dd"},
remove = "a";
boolean gaps[] = new boolean[foo.length];
int newlength = 0;
for (int c = 0; c<foo.length; c++)
{
if (foo[c].equals(remove))
{
gaps[c] = true;
newlength++;
}
else
gaps[c] = false;
System.out.println(foo[c]);
}
String newString[] = new String[newlength];
System.out.println("");
for (int c1=0, c2=0; c1<foo.length; c1++)
{
if (!gaps[c1])
{
newString[c2] = foo[c1];
System.out.println(newString[c2]);
c2++;
}
}
次のような文字列の配列
文字列名= 'abcdeafbde' //文字列名= 'aa bb cde aa f bbde'のようになります
次のクラスを作成します
class clearname{
def parts
def tv
public def str = ''
String name
clearname(String name){
this.name = name
this.parts = this.name.split(" ")
this.tv = this.parts.size()
}
public String cleared(){
int i
int k
int j=0
for(i=0;i<tv;i++){
for(k=0;k<tv;k++){
if(this.parts[k] == this.parts[i] && k!=i){
this.parts[k] = '';
j++
}
}
}
def str = ''
for(i=0;i<tv;i++){
if(this.parts[i]!='')
this.str += this.parts[i].trim()+' '
}
return this.str
}}
return new clearname(name).cleared()
この結果を得る
abcdef
このコードが誰かに役立つことを願っていますよろしく
要素の順序は関係ありません。要素foo [x]とfoo [0]を交換してから、foo.drop(1)を呼び出すことができます。
foo.drop(n)
配列から(n)個の最初の要素を削除します。
これが最も簡単でリソース効率の良い方法だと思います。
PS:indexOf
多くの方法で実装できます。これは私のバージョンです。
Integer indexOf(String[] arr, String value){
for(Integer i = 0 ; i < arr.length; i++ )
if(arr[i] == value)
return i; // return the index of the element
return -1 // otherwise -1
}
while (true) {
Integer i;
i = indexOf(foo,"a")
if (i == -1) break;
foo[i] = foo[0]; // preserve foo[0]
foo.drop(1);
}