it-swarm-eu.dev

Jak odstraním objekty z pole v jazyce Java?

Vzhledem k matici n Objects řekněme, že se jedná o pole řetězců , a má následující hodnoty:

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

Co musím udělat, abych odstranil/odstranil všechny řetězce/objekty rovné "a" v poli?

72
ramayac

[Pokud chcete kód připravený k použití, přejděte na stránku "Edit3" (po střihu). Zbytek je tady pro potomky.]

Vyplnit Dustmanův nápad :

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

Edit: Nyní používám Arrays.asList místo Collections.singleton: singleton je omezen na jednu položku, zatímco přístup asList vám umožňuje přidat další řetězce, které se budou filtrovat později: Arrays.asList("a", "b", "c").

Edit2: Výše ​​uvedený přístup zachovává stejné pole (takže pole je stále stejné délky); element po posledním nastaven na null. Chcete-li, aby bylo pole new dimenzováno přesně podle potřeby, použijte toto místo:

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

Edit3: Pokud tento kód používáte častěji ve stejné třídě, můžete zvážit jeho přidání do vaší třídy:

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

Pak se funkce stane:

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

To pak zastaví odhazování haldy s zbytečnými prázdnými řetězci řetězců, které by jinak byly newed pokaždé, když je volána funkce.

cynicalmanův návrh (viz komentáře) také pomůže s haldy odhazování a pro spravedlnost bych to měl zmínit:

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

Dávám přednost mému přístupu, protože to může být snazší dostat explicitní velikost špatně (např. Volání size() na nesprávném seznamu).

103

Alternativa v jazyce Java 8: 

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

Vytvořte List z pole s Arrays.asList() a volejte remove() na všech příslušných prvcích. Pak zavolejte toArray() na 'List', abyste se opět vrátili do pole.

Není to strašně výkonný, ale pokud ho zapouzdříte správně, můžete vždy později udělat něco rychlejšího.

20
Dustman

Vždy můžete:

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

Můžete použít externí knihovnu:

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

Je v projektu Apache Commons Lang http://commons.Apache.org/lang/

7
bugs_

Viz kód níže

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

Pokud potřebujete odstranit více prvků z pole bez převodu na List, ani vytvořit další pole, můžete to provést v O(n), nezávislý na počtu položek, které chcete odebrat.

a je počáteční pole, int... r jsou odlišné uspořádané indexy (pozice) prvků, které mají být odstraněny:

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

Malé testování:

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]

Ve vašem úkolu můžete nejprve skenovat pole, abyste shromáždili pozice „a“, pak zavolejte removeItems()

4
Alex Salauyou

Něco o tom, že seznam se pak odstraní a pak zpátky do pole mě zasáhne jako špatné. Nebyly testovány, ale myslím, že následující bude lepší. Ano, nejspíš je to příliš pre-optimalizace.

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

Uvědomuji si, že je to velmi starý příspěvek, ale některé z odpovědí mi pomohly, takže tady je moje tuppence 'ha'penny!

Snažil jsem se, aby to fungovalo už nějakou dobu předtím, než jsem začal kopat, že pole, které píšu zpět, muselo být změněno, pokud změny provedené v ArrayList nezanechají velikost seznamu beze změny.

Pokud ArrayList, které upravujete, skončí s větším nebo menším množstvím prvků, než začalo, řádek List.toArray() způsobí výjimku, takže potřebujete něco jako List.toArray(new String[] {}) nebo List.toArray(new String[0]), abyste vytvořili pole s novou (správnou) velikostí.

Zní to teď, když to vím. Není tak zjevné, že by nováček Android/Java, který se dostává do styku s novými a neznámými konstrukty kódů, a který není zřejmý z některých dřívějších příspěvků, tak chtěl, aby byl tento bod opravdu jasný pro každého, kdo se po několik hodin poškrábal na hlavách. !

2
DDSports

UPRAVIT:

Bod s nulls v poli byl vymazán. Omlouváme se za mé komentáře. 

Originál:

Ehm ... linka

array = list.toArray(array);

nahradí všechny mezery v poli, kde byl odstraněný prvek pomocí null . To může být nebezpečné , protože prvky jsou odstraněny, ale délka pole zůstává stejná!

Chcete-li se tomu vyhnout, použijte nový parametr Array jako parametr toArray (). Pokud nechcete použít removeAll, bude sada alternativou:

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

Dává:

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

Kde je současná přijímaná odpověď od výstupů Chris Yester Young:

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

s kódem

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

bez nulových hodnot.

1
GHad

Je zde mnoho odpovědí - problém, jak vidím, je to, že jste neřekli, proč používáte pole namísto sbírky, takže mi dovolte navrhnout pár důvodů a jaká řešení se použijí (Většina řešení již byly zodpovězeny v dalších otázkách, takže nebudu jít příliš podrobně):

důvod: Nevěděli jste, že balíček kolekce existoval nebo mu nedůvěřoval

řešení: Použijte kolekci. 

Pokud máte v plánu přidávat/mazat uprostřed, použijte LinkedList. Pokud se opravdu bojíte o velikost nebo často index přímo do středu kolekce, použijte ArrayList. Obě tyto operace by měly odstranit operace.

důvod: Jste znepokojeni velikostí nebo chcete ovládat přidělení paměti

řešení: Použijte ArrayList se specifickou počáteční velikostí.

ArrayList je prostě pole, které se může rozšířit, ale nemusí to vždy dělat. Bude velmi chytré přidávat/odebírat položky, ale pokud znovu vložíte/odstraníte LOT ze středu, použijte LinkList.

reason: Máte pole přicházející do pole a pole, které jde ven, takže chcete pracovat na poli

řešení: Převést ji na ArrayList, odstranit položku a převést ji zpět

důvod: Myslíte si, že pokud to uděláte sami, můžete napsat lepší kód

řešení: nemůžete použít seznam nebo propojený seznam.

důvod: toto je přiřazení třídy a vy nejste povoleni nebo nemáte přístup do sbírky apis z nějakého důvodu

předpoklad: Potřebujete nové pole, které bude správné "velikost"

řešení: Naskenujte pole pro odpovídající položky a spočítejte je. Vytvořte nové pole správné velikosti (původní velikost - počet shod). opakovaně používejte System.arraycopy, abyste zkopírovali každou skupinu položek, které chcete zachovat v novém poli. Pokud se jedná o přiřazení třídy a nemůžete použít System.arraycopy, zkopírujte je po jednom ručně do smyčky, ale nikdy to neudělejte ve výrobním kódu, protože je to mnohem pomalejší. (Tato řešení jsou podrobně popsána v dalších odpovědích)

důvod: je třeba spustit holý kov

předpoklad: nesmíte zbytečně přidělit prostor nebo trvat příliš dlouho

předpoklad: Sledujete velikost používanou v matici (délka) odděleně, protože jinak byste museli přiřadit pole pro odstranění/vložení.

Příklad, proč to chcete udělat: jediné pole primitivů (řekněme int hodnoty) bere významný kus vašeho berana - jako 50%! ArrayList by je nutil do seznamu ukazatelů na Integer objekty, které by využívaly několikrát větší množství paměti.

řešení: Iterace přes pole a vždy, když najdete prvek, který chcete odstranit (pojďme to nazývat element n), použijte System.arraycopy pro zkopírování ocasu pole nad element "smazaný" (Zdroj a Cíl jsou stejné pole) - to je natolik chytrý, aby kopii provedl správným směrem, takže paměť sama o sobě nepřepíše:

 System.arraycopy (ary, n + 1, ary, n, délka-n) 
 Délka -; 

Pravděpodobně budete chtít být chytřejší než toto, pokud odstraňujete více než jeden prvek najednou. Ty by jen pohybovat oblast mezi jedním "zápas" a další spíše než celý ocas a jako vždy, vyhnout se pohybující se každý kus dvakrát.

V tomto posledním případě musíte absolutně dělat svou práci sami, a pomocí System.arraycopy je opravdu jediný způsob, jak to udělat, protože to bude vybrat nejlepší možný způsob, jak přesunout paměť pro vaši architekturu počítače - to by mělo být mnohokrát rychlejší než jakýkoli kód, který byste mohli rozumně napsat sami.

1
Bill K

Můj malý příspěvek k tomuto problému.

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, nemohu dostat kód, aby se ukázal správně. Promiň, fungovalo to. Znovu se omlouvám, nemyslím si, že jsem otázku správně přečetla.

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

Zkopíruje všechny prvky s výjimkou indexu 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

Počáteční pole 

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

pokud chcete odstranit 51, který je index 2, použijte následující

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

Záleží na tom, co tím myslíš "odstranit"? Pole je konstrukt s pevnou velikostí - nemůžete změnit počet prvků v něm. Takže můžete buď: a) vytvořit nové, kratší pole bez prvků, které nechcete, nebo b) přiřadit položky, které nechcete, k něčemu, co označuje jejich stav „prázdný“; obvykle null, pokud nepracujete s primitivy.

V prvním případě vytvořte seznam z pole, odeberte prvky a vytvořte nové pole ze seznamu. Pokud je výkon důležitý iterovat přes pole přiřazující všechny prvky, které by neměly být odebrány do seznamu, a potom vytvořit nové pole ze seznamu. V druhém případě jednoduše projděte a přiřaďte k položkám pole null.

0
DJClayworth