web-dev-qa-db-de.com

Wie entferne ich Objekte aus einem Array in Java?

Angenommen, ein Array von n -Objekten ist ein -Array von Strings, und es hat die folgenden Werte:

foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";

Was muss ich tun, um alle Strings/Objekte zu löschen, die gleich "a" im Array sind?

72
ramayac

[Wenn Sie gebrauchsfertigen Code wünschen, scrollen Sie bitte zu meinem "Edit3" (nach dem Schnitt). Der Rest ist für die Nachwelt da.]

Ausarbeiten Dustmans Idee :

List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);

Bearbeiten: Ich benutze jetzt Arrays.asList anstelle von Collections.singleton: Singleton ist auf einen Eintrag beschränkt, wohingegen der Ansatz asList Ihnen erlaubt, andere Zeichenfolgen hinzuzufügen, die später herausgefiltert werden: Arrays.asList("a", "b", "c").

Edit2: Der obige Ansatz behält das gleiche Array bei (das Array hat also immer noch die gleiche Länge). Das Element nach dem letzten wird auf null gesetzt. Wenn Sie möchten, dass ein new -Array genau so groß ist wie erforderlich, verwenden Sie stattdessen Folgendes:

array = list.toArray(new String[0]);

Edit3: Wenn Sie diesen Code häufig in derselben Klasse verwenden, sollten Sie dies in Ihre Klasse aufnehmen:

private static final String[] EMPTY_STRING_ARRAY = new String[0];

Dann wird die Funktion:

List<String> list = new ArrayList<>();
Collections.addAll(list, array);
list.removeAll(Arrays.asList("a"));
array = list.toArray(EMPTY_STRING_ARRAY);

Dadurch wird der Heap nicht mehr mit unnötigen leeren String-Arrays belegt, die andernfalls bei jedem Aufruf Ihrer Funktion newed wären.

der Vorschlag von Cynicalman (siehe Kommentare) hilft auch bei der Verschwendung von Haufen, und aus Gründen der Fairness sollte ich es erwähnen:

array = list.toArray(new String[list.size()]);

Ich bevorzuge meinen Ansatz, weil es einfacher sein kann, die explizite Größe falsch zu ermitteln (z. B. Aufruf von size() in der falschen Liste).

103

Eine Alternative in Java 8: 

String[] filteredArray = Arrays.stream(array)
    .filter(e -> !e.equals(foo)).toArray(String[]::new);
27

Machen Sie mit Arrays.asList() eine List aus dem Array und rufen Sie remove() für alle entsprechenden Elemente auf. Rufen Sie dann toArray() in der 'Liste' auf, um wieder ein Array zu erstellen.

Nicht besonders leistungsfähig, aber wenn Sie es richtig verkapseln, können Sie später immer etwas schneller machen.

20
Dustman

Sie können immer tun:

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);
13
anon

Sie können eine externe Bibliothek verwenden:

org.Apache.commons.lang.ArrayUtils.remove(Java.lang.Object[] array, int index)

Es befindet sich im Projekt Apache Commons Lang http://commons.Apache.org/lang/

7
bugs_

Siehe Code unten

ArrayList<String> a = new ArrayList<>(Arrays.asList(strings));
a.remove(i);
strings = new String[a.size()];
a.toArray(strings);
5
Ali

Wenn Sie mehrere Elemente aus einem Array entfernen müssen, ohne es in List zu konvertieren oder ein zusätzliches Array zu erstellen, können Sie dies in O(n) tun, unabhängig von der Anzahl der zu entfernenden Elemente.

Hier ist a das Anfangsarray, int... r sind verschiedene geordnete Indizes (Positionen) der zu entfernenden Elemente:

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"
}  

Kleine prüfung:

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]

In Ihrer Aufgabe können Sie zuerst das Array scannen, um die Positionen von "a" zu erfassen, und dann removeItems() aufrufen. 

4
Alex Salauyou

Etwas über das Erstellen einer Liste, das dann entfernt wird und dann wieder in ein Array eingefügt wird, erscheint mir falsch. Habe nicht getestet, aber ich denke, dass die folgenden Ergebnisse besser abschneiden werden. Ja, ich bin wahrscheinlich übermäßig voroptimierend.

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];
   }
}
3
shsteimer

Mir ist klar, dass dies ein sehr alter Beitrag ist, aber einige der Antworten hier haben mir geholfen, also hier ist mein Wert!

Ich hatte Mühe, dieses Problem für eine Weile zu lösen, bevor ich das Twigging machte, dass die Größe des Arrays, in das ich schreibe, geändert werden musste, es sei denn, die Änderungen, die an der Variablen ArrayList vorgenommen wurden, lassen die Listengröße unverändert.

Wenn die ArrayList, die Sie ändern, mehr oder weniger Elemente enthält, als sie begonnen haben, wird die Zeile List.toArray() eine Ausnahme auslösen, sodass Sie etwas wie List.toArray(new String[] {}) oder List.toArray(new String[0]) benötigen, um ein Array mit der neuen (korrekten) Größe zu erstellen.

Klingt offensichtlich, jetzt wo ich es weiß. Für einen Android/Java-Neuling nicht so offensichtlich, der sich mit neuen und unbekannten Code-Konstrukten auseinandersetzt, und nicht offensichtlich aus einigen der früheren Beiträge hier. Deshalb wollte ich diesen Punkt für alle anderen, die sich stundenlang den Kopf zerkratzen, genau so klar machen wie ich !

2
DDSports

BEARBEITEN:

Der Punkt mit den Nullen im Array wurde gelöscht. Entschuldigung für meine Kommentare. 

Original:

Ähm ... die Linie

array = list.toArray(array);

ersetzt alle Lücken im Array, in denen das entfernte Element vorhanden war, durch null . Dies kann gefährlich sein, da die Elemente entfernt werden, die Länge des Arrays jedoch gleich bleibt!

Wenn Sie dies vermeiden möchten, verwenden Sie ein neues Array als Parameter für toArray (). Wenn Sie removeAll nicht verwenden möchten, wäre ein Set eine Alternative:

        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));

Gibt:

[a, bc, dc, a, ef]
[dc, ef, bc]

Wo wie die aktuell akzeptierte Antwort von Chris Yester Young Ausgaben:

[a, bc, dc, a, ef]
[bc, dc, ef, null, ef]

mit dem Code

    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));

ohne Nullwerte zurückgelassen.

1
GHad

Hier gibt es viele Antworten - das Problem, das ich sehe, ist, dass Sie nicht gesagt haben, WARUM Sie ein Array anstelle einer Sammlung verwenden. Lassen Sie mich daher ein paar Gründe nennen, und welche Lösungen zutreffen würden (die meisten Lösungen) wurden bereits in anderen Fragen hier beantwortet, daher gehe ich nicht zu sehr ins Detail):

Grund: Sie haben nicht gewusst, dass das Collection-Paket existiert hat oder nicht vertraute

lösung: Verwenden Sie eine Sammlung. 

Wenn Sie aus der Mitte hinzufügen/löschen möchten, verwenden Sie eine LinkedList. Wenn Sie sich wirklich Sorgen um die Größe machen oder oft mitten in der Sammlung indexieren, verwenden Sie eine ArrayList. Beide sollten Löschvorgänge haben.

Grund: Sie sind besorgt über die Größe oder möchten die Speicherzuordnung kontrollieren

lösung: Verwenden Sie eine ArrayList mit einer bestimmten Anfangsgröße.

Eine ArrayList ist einfach ein Array, das sich erweitern kann, dies muss jedoch nicht immer geschehen. Das Hinzufügen/Entfernen von Elementen ist sehr schlau. Wenn Sie jedoch eine LOT aus der Mitte einfügen/entfernen, verwenden Sie eine LinkedList.

Grund: Sie haben ein Array und ein Array - Sie wollen ein Array bearbeiten

lösung: Konvertieren Sie es in eine ArrayList, löschen Sie das Element und konvertieren Sie es zurück

Grund: Du denkst, du kannst besseren Code schreiben, wenn du es selbst machst

lösung: Sie können kein Array oder eine verknüpfte Liste verwenden.

reason: Dies ist eine Klassenzuordnung und Sie sind aus irgendeinem Grund nicht berechtigt oder Sie haben keinen Zugriff auf die Sammlung apis

annahme: Das neue Array muss die richtige "Größe" haben.

lösung: Durchsuchen Sie das Array nach übereinstimmenden Elementen und zählen Sie diese. Erstellen Sie ein neues Array mit der richtigen Größe (Originalgröße - Anzahl der Übereinstimmungen). Verwenden Sie System.arraycopy wiederholt, um jede Gruppe von Elementen, die Sie behalten möchten, in Ihr neues Array zu kopieren. Wenn dies eine Klassenzuweisung ist und Sie System.arraycopy nicht verwenden können, kopieren Sie sie einfach einzeln in einer Schleife von Hand, tun Sie dies jedoch niemals im Produktionscode, da sie viel langsamer ist. (Diese Lösungen werden in anderen Antworten beschrieben.)

Grund: Du musst nacktes Metall laufen lassen

annahme: Sie MÜSSEN nicht unnötig Speicherplatz zuweisen oder zu lange dauern

annahme: Sie verfolgen die im Array verwendete Größe (Länge) separat, da Sie das Array sonst für Löschungen/Einfügungen neu zuordnen müssen.

Ein Beispiel dafür, warum Sie dies vielleicht tun möchten: Ein einziges Array von Primitiven (beispielsweise int-Werte) nimmt einen erheblichen Teil Ihres RAM-Speichers ein - etwa 50%! Eine ArrayList würde diese in eine Liste von Zeigern auf Integer-Objekte zwingen, die ein paar Mal so viel Speicher benötigen.

lösung: Durchlaufen Sie Ihr Array und wann immer Sie ein Element finden, das Sie entfernen möchten (nennen wir es Element n), verwenden Sie System.arraycopy, um das Ende des Arrays über das "gelöschte" Element (Quelle und Ziel sind dasselbe Array) zu kopieren ist intelligent genug, um die Kopie in der richtigen Richtung auszuführen, damit sich der Speicher nicht selbst überschreibt:

 System.arraycopy (ary, n + 1, ary, n, length-n) 
 Länge--;

Sie möchten wahrscheinlich intelligenter sein, wenn Sie mehrere Elemente gleichzeitig löschen. Sie würden nur den Bereich zwischen einem "Match" und dem nächsten und nicht dem gesamten Schwanz verschieben. Vermeiden Sie es wie üblich, einen Abschnitt zweimal zu verschieben.

In diesem letzten Fall müssen Sie die Arbeit unbedingt selbst erledigen, und System.arraycopy ist wirklich die einzige Möglichkeit, da dies die beste Möglichkeit ist, den Speicher für Ihre Computerarchitektur zu verschieben - es sollte um ein Vielfaches schneller sein als jeder Code, den Sie selbst schreiben könnten.

1
Bill K

Mein kleiner Beitrag zu diesem Problem.

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;
}

}

1
Andre

Arrgh, ich kann den Code nicht richtig anzeigen. Entschuldigung, ich habe es funktioniert. Sorry nochmal, ich glaube nicht, dass ich die Frage richtig gelesen habe.

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++;
    }
}
0
AngelOfCake

Wenn es nicht auf die Reihenfolge der Elemente ankommt. Sie können zwischen den Elementen foo [x] und foo [0] wechseln und dann foo.drop (1) aufrufen.

foo.drop(n) entfernt (n) erste Elemente aus dem Array.

Ich denke, dies ist der einfachste und ressourceneffizienteste Weg.

PS: indexOf kann auf viele Arten implementiert werden, dies ist meine Version.

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);
}
0
milevyo

Kopiert alle Elemente außer dem mit dem Index 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) );
            }
0
PauLy

In einer Reihe von Strings wie

String name = 'a b c d e a b d e' // könnte sein wie String name = 'aa b b c d e

Ich baue die folgende Klasse

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()

dieses Ergebnis erhalten

a b c d e f

hoffe, dieser Code hilft jemandem Grüße

0
Orlando Reyes

Anfangsfeld 

   int[] array = {5,6,51,4,3,2};

wenn Sie 51 entfernen möchten (Index 2), verwenden Sie folgendes

 for(int i = 2; i < array.length -1; i++){
    array[i] = array[i + 1];
  }
0
Ebin Joy

Kommt drauf an was du mit "entfernen" meinst? Ein Array ist ein Konstrukt mit fester Größe - Sie können die Anzahl der darin enthaltenen Elemente nicht ändern. Sie können also entweder a) ein neues, kürzeres Array ohne die Elemente erstellen, die Sie nicht möchten, oder b) die Einträge, die Sie nicht möchten, einem Element zuweisen, das ihren "leeren" Status anzeigt. normalerweise null, wenn Sie nicht mit Grundelementen arbeiten.

Im ersten Fall erstellen Sie eine Liste aus dem Array, entfernen Sie die Elemente und erstellen Sie ein neues Array aus der Liste. Wenn Leistung wichtig ist, iterieren Sie das Array, und ordnen Sie der Liste Elemente zu, die nicht entfernt werden sollen. Erstellen Sie dann ein neues Array aus der Liste. Im zweiten Fall gehen Sie einfach durch und weisen den Feldeinträgen Null zu.

0
DJClayworth