web-dev-qa-db-fra.com

Comment supprimer des objets d'un tableau en Java?

Etant donné un tableau de n Objects, supposons que c'est un tableau de chaînes , et qu'il a les valeurs suivantes:

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

Que dois-je faire pour supprimer/supprimer toutes les chaînes/objets égaux à "a" dans le tableau?

72
ramayac

[Si vous voulez du code prêt à l'emploi, s'il vous plaît faites défiler jusqu'à mon "Edit3" (après la coupe). Le reste est là pour la postérité.]

Pour étoffer l'idée de Dustman :

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

Edit: J'utilise maintenant Arrays.asList au lieu de Collections.singleton: le singleton est limité à une entrée, alors que l'approche asList vous permet d'ajouter d'autres chaînes à filtrer ultérieurement: Arrays.asList("a", "b", "c").

Edit2: L'approche ci-dessus conserve le même tableau (le tableau a donc toujours la même longueur); l'élément après le dernier est défini sur null. Si vous voulez un tableau new de la taille exacte, utilisez plutôt ceci:

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

Edit3: Si vous utilisez fréquemment ce code dans la même classe, vous pouvez envisager de l’ajouter à votre classe:

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

Alors la fonction devient:

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

Cela évitera alors de surcharger votre segment de mémoire avec des tableaux de chaînes vides inutiles qui, autrement, seraient newed à chaque appel de votre fonction.

la suggestion de cynicalman (voir les commentaires) aidera également à éliminer les déchets, et pour être juste, je devrais le mentionner:

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

Je préfère mon approche, car il peut être plus facile de se tromper de taille explicite (par exemple, en appelant size() sur la mauvaise liste).

103
Chris Jester-Young

Une alternative en Java 8: 

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

Créez une List du tableau avec Arrays.asList() et appelez remove() sur tous les éléments appropriés. Appelez ensuite toArray() dans la liste pour revenir dans un tableau.

Pas très performant, mais si vous l’encapsulez correctement, vous pourrez toujours faire quelque chose de plus vite plus tard.

20
Dustman

Vous pouvez toujours faire:

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

Vous pouvez utiliser une bibliothèque externe:

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

C'est dans le projet Apache Commons Lang http://commons.Apache.org/lang/

7
bugs_

Voir le code ci-dessous

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

Si vous devez supprimer plusieurs éléments d'un tableau sans le convertir en List ni créer de tableau supplémentaire, vous pouvez le faire dans O(n) en fonction du nombre d'éléments à supprimer.

Ici, a est le tableau initial, int... r sont des index ordonnés distincts (positions) des éléments à supprimer:

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

Petit test:

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]

Dans votre tâche, vous pouvez d’abord scanner un tableau pour collecter les positions de "a", puis appeler removeItems()

4
Alex Salauyou

Quelque chose à propos de la liste puis de l'enlever puis de revenir à un tableau me semble erroné. N'a pas été testé, mais je pense que ce qui suit sera plus performant. Oui, je suis probablement en train de pré-optimiser indûment.

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

Je réalise que c'est un très vieux billet, mais certaines des réponses ici m'ont aidé, alors voici la valeur de ma tuppence 'ha'penny!

J'ai eu du mal à obtenir que cela fonctionne pendant un bon bout de temps avant de penser que le tableau dans lequel je suis en train d'écrire devait être redimensionné, à moins que les modifications apportées à la variable ArrayList ne modifient pas la taille de la liste.

Si la ArrayList que vous modifiez se termine avec un nombre d'éléments supérieur ou inférieur au nombre initial, la ligne List.toArray() provoquera une exception. Vous avez donc besoin de quelque chose comme List.toArray(new String[] {}) ou List.toArray(new String[0]) pour créer un tableau avec la nouvelle taille (correcte).

Cela semble évident maintenant que je le sais. Pas si évident pour un débutant sous Android/Java qui est en train de se familiariser avec des constructions de code nouvelles et inconnues et comme cela n’est pas évident dans certains posts précédents, je voulais donc que ce point soit vraiment clair pour quiconque se gratter la tête pendant des heures comme j’étais !

2
DDSports

MODIFIER:

Le point avec les valeurs NULL dans le tableau a été effacé. Désolé pour mes commentaires. 

Original:

Euh ... la ligne

array = list.toArray(array);

remplace tous les espaces dans le tableau où l'élément supprimé a été avec null . Cela peut être dangereux , car les éléments sont supprimés, mais la longueur du tableau reste la même!

Si vous voulez éviter cela, utilisez un nouveau tableau comme paramètre pour toArray (). Si vous ne voulez pas utiliser removeAll, un ensemble serait une 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));

Donne:

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

Où comme réponse actuelle acceptée de Chris Yester Young produit:

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

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

sans aucune valeur nulle laissée derrière.

1
GHad

Il y a beaucoup de réponses ici - le problème car je vois que c'est que vous n'avez pas dit POURQUOI vous utilisez un tableau au lieu d'une collection, laissez-moi vous suggérer quelques raisons et les solutions qui s'appliqueraient (La plupart des solutions déjà été répondu dans d'autres questions ici, donc je ne vais pas trop entrer dans les détails):

raison: vous ne saviez pas que le paquet de collecte existait ou ne vous y fiez pas

solution: Utilisez une collection. 

Si vous envisagez d’ajouter ou de supprimer du milieu, utilisez une LinkedList. Si vous êtes vraiment préoccupé par la taille ou indexez souvent au milieu de la collection, utilisez un ArrayList. Ces deux doivent avoir des opérations de suppression.

raison: votre taille vous préoccupe ou vous souhaitez contrôler l'allocation de mémoire

solution: Utilisez un ArrayList avec une taille initiale spécifique.

Un ArrayList est simplement un tableau qui peut se développer, mais ce n'est pas toujours nécessaire. Il sera très judicieux d'ajouter/supprimer des éléments, mais encore une fois, si vous insérez/supprimez un LOT au milieu, utilisez une LinkedList.

raison: vous avez un tableau entrant et un tableau sortant - vous voulez donc opérer sur un tableau

solution: convertissez-le en une liste de tableaux, supprimez l'élément et reconvertissez-le

raison: vous pensez que vous pouvez écrire un meilleur code si vous le faites vous-même

solution: vous ne pouvez pas, utiliser un tableau ou une liste liée.

raison: il s'agit d'une tâche de classe et vous n'êtes pas autorisé ou vous n'avez pas accès aux API de collection pour une raison quelconque

hypothèse: le nouveau tableau doit avoir la "taille" correcte

solution: Analysez le tableau pour rechercher les éléments correspondants et comptez-les. Créez un nouveau tableau de la taille correcte (taille d'origine - nombre de correspondances). utilisez plusieurs fois System.arraycopy pour copier chaque groupe d'éléments que vous souhaitez conserver dans votre nouveau tableau. S'il s'agit d'une affectation de classe et que vous ne pouvez pas utiliser System.arraycopy, copiez-les une à la fois à la main dans une boucle, mais ne le faites jamais dans le code de production car il est beaucoup plus lent. (Ces solutions sont détaillées dans d'autres réponses)

raison: vous devez utiliser du métal nu

hypothèse: vous ne devez PAS allouer d'espace inutilement ni prendre trop de temps

hypothèse: vous suivez la taille utilisée dans le tableau (longueur) séparément car sinon, vous devrez réaffecter votre tableau aux suppressions/insertions.

Voici un exemple de pourquoi vous voudrez peut-être faire cela: un seul tableau de primitives (disons des valeurs int) prend une grande partie de votre bélier - comme 50%! Un ArrayList les forcerait dans une liste de pointeurs sur les objets Integer qui utiliseraient une quantité de mémoire égale à quelques fois.

solution: Itérer sur votre tableau et chaque fois que vous trouvez un élément à supprimer (appelons-le élément n), utilisez System.arraycopy pour copier la queue du tableau sur l'élément "supprimé" (Source et Destination sont le même tableau) - il est assez intelligent pour faire la copie dans le bon sens pour que la mémoire ne s’écrase pas elle-même:

 System.arraycopy (ary, n + 1, ary, n, length-n) 
 longueur--;

Vous voudrez probablement être plus intelligent que cela si vous supprimez plusieurs éléments à la fois. Vous ne feriez que déplacer la zone entre les deux parties plutôt que la queue entière et, comme toujours, évitez de déplacer deux fois un morceau.

Dans ce dernier cas, vous devez absolument faire le travail vous-même, et utiliser System.arraycopy est vraiment le seul moyen de le faire, car il va choisir le meilleur moyen de déplacer éventuellement de la mémoire pour l'architecture de votre ordinateur - cela devrait être beaucoup plus rapide que tout code que vous pourriez raisonnablement écrire vous-même.

1
Bill K

Ma petite contribution à ce problème.

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, je ne peux pas obtenir le code pour apparaître correctement. Désolé, ça marche. Désolé encore, je ne pense pas avoir bien lu la question.

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

Si l'ordre des éléments n'a pas d'importance vous pouvez permuter entre les éléments foo [x] et foo [0], puis appelez foo.drop (1).

foo.drop(n) supprime (n) les premiers éléments du tableau.

J'imagine que c'est le moyen le plus simple et le moins gourmand en ressources.

PS: indexOf peut être implémenté de différentes manières, voici ma 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

Copiera tous les éléments sauf celui d'indice 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

Dans un tableau de chaînes comme

Nom de chaîne = 'a b c d e a f b d e' // pourrait ressembler à Chaîne nom = 'aa bb c d e aa f bb d e'

Je construis la classe suivante

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

obtenir ce résultat

a B c d e F

espérons que ce code aide quelqu'un Cordialement

0
Orlando Reyes

Tableau initial 

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

si vous voulez supprimer 51 qui est l'index 2, utilisez la commande suivante

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

Cela dépend de ce que vous entendez par "enlever"? Un tableau est une construction de taille fixe - vous ne pouvez pas changer le nombre d'éléments qu'il contient. Vous pouvez donc a) créer un nouveau tableau plus court sans les éléments que vous ne voulez pas ou b) affecter les entrées que vous ne voulez pas à quelque chose qui indique leur statut «vide»; généralement null si vous ne travaillez pas avec des primitives.

Dans le premier cas, créez une liste à partir du tableau, supprimez les éléments et créez un nouveau tableau à partir de la liste. Si les performances sont importantes, effectuez une itération sur le tableau en affectant les éléments qui ne doivent pas être supprimés à une liste, puis créez un nouveau tableau à partir de la liste. Dans le second cas, il suffit de passer et d’attribuer la valeur null aux entrées du tableau.

0
DJClayworth