Java で配列からオブジェクトを削除するにはどうすればよいですか?
-
02-07-2019 - |
質問
の配列が与えられると、 n オブジェクト、たとえば、 文字列の配列, であり、次の値があります。
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
以下に等しいすべての文字列/オブジェクトを削除するにはどうすればよいですか? 「あ」 配列の中で?
解決
[すぐに使えるコードが必要な場合は、私の「Edit3」(カット後) までスクロールしてください。残りは後世のためにここにあります。]
肉付けする ダストマンのアイデア:
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")
.
編集2:上記のアプローチでは同じ配列が保持されます (つまり、配列の長さは同じままです)。最後の要素の後の要素は null に設定されます。ご希望の場合は、 新しい 必要なサイズの配列を指定するには、代わりにこれを使用します。
array = list.toArray(new String[0]);
編集3:同じクラス内でこのコードを頻繁に使用する場合は、これをクラスに追加することを検討してください。
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);
作る List
配列の外に Arrays.asList()
, 、そして電話します remove()
適切なすべての要素について。それから電話してください toArray()
「リスト」を再度配列に戻します。
それほどパフォーマンスは高くありませんが、適切にカプセル化しておけば、後でいつでもより迅速に何かを行うことができます。
いつでも次のことができます。
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)
Apache Commons Lang プロジェクトにあります http://commons.apache.org/lang/
以下のコードを参照してください
ArrayList<String> a = new ArrayList<>(Arrays.asList(strings));
a.remove(i);
strings = new String[a.size()];
a.toArray(strings);
配列を変換せずに配列から複数の要素を削除する必要がある場合 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()
.
リストを作成してから削除し、配列に戻すということについての何かが間違っているように思えます。テストはしていませんが、以下の方がパフォーマンスが良いと思います。はい、おそらく過度に事前最適化を行っています。
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];
}
}
これが非常に古い投稿であることは承知していますが、ここでの回答のいくつかが私を助けてくれたので、ここに私のタペンス、半ペニーの価値があります!
これを機能させるのにかなり長い間苦労しましたが、その後、書き戻す配列のサイズを変更する必要があることに気づきました。 ArrayList
リストのサイズは変更しないでください。
もし ArrayList
変更中の要素は、最初よりも多くなったり、少なくなったりすることになります。 List.toArray()
例外が発生するため、次のようなものが必要です List.toArray(new String[] {})
または List.toArray(new String[0])
新しい (正しい) サイズの配列を作成するため。
今知ったら当然のように聞こえます。新しい、なじみのないコード構造を理解しようとしている Android/Java 初心者にとってはそれほど明白ではありませんし、ここでの以前の投稿のいくつかからは明白ではありませんでした。そのため、私と同じように何時間も頭を悩ませている他の人のためにこの点を明確にしたいと思っただけです。 !
ここにはたくさんの答えがあります。私が見たところの問題は、なぜコレクションではなく配列を使用しているのかを述べていないことです。そこで、いくつかの理由とどの解決策が適用されるかを提案しましょう(ほとんどの解決策はここの他の質問ですでに回答されているため、詳しくは説明しません)。
理由:コレクション パッケージの存在を知らなかったか、信頼していませんでした
解決:コレクションを使用します。
途中から追加・削除する場合は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) length--;
一度に複数の要素を削除する場合は、おそらくこれよりも賢明な方がよいでしょう。末尾全体ではなく、ある「一致」と次の「一致」の間の領域のみを移動し、いつものように、チャンクを 2 回移動することは避けます。
この最後のケースでは、作業は絶対に自分で行う必要があり、実際には System.arraycopy を使用することが唯一の方法です。これは、コンピュータ アーキテクチャに合わせてメモリを移動する最善の方法が選択されるためです。これにより、何倍も高速になるはずです。自分で無理なく書けるどんなコードよりも。
編集:
配列内の null を含むポイントはクリアされました。コメント失礼します。
オリジナル:
えーっと…この線
array = list.toArray(array);
削除された要素が存在していた配列内のすべてのギャップを置き換えます。 ヌル. 。これはもしかしたら 危険な, 要素は削除されますが、配列の長さは同じままであるためです。
これを回避したい場合は、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;
}
}
初期配列
int[] array = {5,6,51,4,3,2};
インデックス 2 である 51 を削除したい場合は、次を使用します
for(int i = 2; i < array.length -1; i++){
array[i] = array[i + 1];
}
それは「削除」が何を意味するかによって異なりますか?配列は固定サイズの構造体であり、その中の要素の数を変更することはできません。したがって、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++;
}
}
インデックス i を持つ要素を除くすべての要素をコピーします。
if(i == 0){
System.arraycopy(edges, 1, copyEdge, 0, edges.length -1 );
}else{
System.arraycopy(edges, 0, copyEdge, 0, i );
System.arraycopy(edges, i+1, copyEdge, i, edges.length - (i+1) );
}
次のような文字列の配列で
String name = 'a b c d e a f b d e' // String name = 'aa bb c d e aa f bb d e' のようにすることもできます
次のクラスを構築します
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()
この結果が得られる
a b c d e f
このコードが誰にでもよろしくお願いします
class sd
{
public static void main(String[ ] args)
{
System.out.println("Search and Delete");
int key;
System.out.println("Enter the length of array:");
Scanner in=new Scanner(System.in);
int n=in.nextInt();
int numbers[]=new int[n];
int i = 0;
boolean found = false;
System.out.println("Enter the elements in Array :");
for ( i = 0; i < numbers.length; i++)
{
numbers[i]=in.nextInt();
}
System.out.println("The elements in Array are:");
for ( i = 0; i < numbers.length; i++)
{
System.out.println(numbers[i]);
}
System.out.println("Enter the element to be searched:");
key=in.nextInt();
for ( i = 0; i < numbers.length; i++)
{
if (numbers[ i ] == key)
{
found = true;
break;
}
}
if (found)
{
System.out.println("Found " + key + " at index " + i + ".");
numbers[i]=0;//haven't deleted the element in array
System.out.println("After Deletion:");
for ( i = 0; i < numbers.length; i++)
{
if (numbers[ i ]!=0)
{ //it skips displaying element in array
System.out.println(numbers[i]);
}
}
}
else
{
System.out.println(key + "is not in this array.");
}
}
}//Sorry.. if there are mistakes.
使用:
list.removeAll(...);
//post what char you need in the ... section
配列の位置に null を割り当てます。