2008-09-21 12 views
67

Dada una matriz de n objetos, digamos que es una matriz de cadenas, y tiene los siguientes valores:¿Cómo elimino objetos de una matriz en Java?

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

¿Qué tengo que hacer para eliminar/eliminar todas las cuerdas/objetos igual a "a" en la matriz?

+2

No se puede cambiar el tamaño de una matriz en Java. Supongo que no quieres simplemente anular los elementos ya que eso sería trivial. ¿Desea cambiar los otros elementos para eliminar los huecos? –

+1

Es trivial, ahora que sé que puedo hacerlo. ;) ¡Gracias! – ramayac

Respuesta

96

[Si desea un código listo para usar, desplácese a mi "Editar3" (después del corte). El resto está aquí para la posteridad]

para dar cuerpo a Dustman's idea:.

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

Editar: Ahora estoy usando en lugar de Arrays.asListCollections.singleton: Singleton se limita a una entrada, mientras que el enfoque asList le permite agregue otras cadenas para filtrar más tarde: Arrays.asList("a", "b", "c").

Edit2: El enfoque anterior conserva la misma matriz (por lo que la matriz sigue siendo la misma longitud); el elemento después de la última se establece en nulo. Si quieres un nueva matriz dimensionada exactamente como sea necesario, utilizar esto en su lugar:

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

Edit3: si utiliza este código de forma frecuente en la misma clase, es posible que desee considerar la adición de este a su clase:

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

Entonces, la función se convierte en:

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

Esto dejará de ensuciar tu montón con matrices de cadenas vacías inútiles que de lo contrario serían new ed cada vez que se llame a tu función. sugerencia

de cynicalman (ver comentarios) también ayudará con la basura montón, y para ser justos, se debe mencionar que:

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

prefiero mi enfoque, ya que puede ser más fácil de obtener el tamaño explícita mal (por ejemplo, llamando al size() en la lista incorrecta).

+0

Me alegro de que le haya gustado. Revisé mi entrada para admitir la eliminación de _todas las instancias de "a", no solo la primera. :-) –

+0

Ooff ... derribado en la línea de meta. Sabía que debería haber seguido editando. Este sistema lleva un tiempo acostumbrándose. ¡Buena edición! – Dustman

+0

GHad: ¿Has leído mi Edit2 arriba? Se trata exactamente de lo que mencionaste, y se publicó antes de tu publicación. –

20

Realice una List fuera de la matriz con Arrays.asList(), y llame al remove() en todos los elementos apropiados. Luego llame al toArray() en la 'Lista' para volver a hacer una matriz.

No es muy eficaz, pero si lo encapsula correctamente, siempre puede hacer algo más rápido más adelante.

+3

Re tu comentario: Está bien, te acostumbrarás pronto. :-) Publiqué mi publicación porque no quería que los lectores tuvieran la idea de que los elementos pueden eliminarse del resultado de Arrays.asList() (es una lista inmutable), así que pensé que un ejemplo podría solucionarlo. :-) –

+0

Uh, me refería a la lista no redimensionable (add() y remove() no funcionan). :-P Todavía tiene un método set() utilizable. :-) –

+0

Aunque pueda parecer extraño, mi experiencia es que la penalización de rendimiento de este enfoque es mínima. –

-6

Asigne nulo a las ubicaciones de la matriz.

+2

¿Podría explicarlo? – ramayac

3

Algo acerca de hacer una lista de ello, luego eliminar y volver a una matriz me parece erróneo. No he probado, pero creo que los siguientes tendrán un mejor rendimiento. Sí, probablemente estoy optimizando demasiado.

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

Arrgh, no consigo que el código se muestre correctamente. Lo siento, lo tengo funcionando.Perdón otra vez, no creo haber leído la pregunta correctamente.

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

EDIT:

El punto con los nulos de la matriz se ha despejado. Perdón por mis comentarios

original:

Ehm ... la línea

array = list.toArray(array); 

reemplaza todos los huecos de la matriz donde el elemento retirado ha sido nula con . Esto podría ser peligroso, porque los elementos se eliminan, pero la longitud de la matriz sigue siendo la misma.

Si desea evitar esto, use una nueva matriz como parámetro para toArray(). Si usted don `t desea utilizar removeAll, un conjunto sería una alternativa:

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

Da:

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

Donde como la corriente respuesta aceptada de las salidas de Chris Yester jóvenes:

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

con el código

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

wi sin ningún valor nulo dejado atrás.

+0

Buen intento, pero no cigarro. Publiqué una edición sobre exactamente este tema, mucho antes de que hicieras tu publicación. Entonces, aunque eres "técnicamente correcto", no aprecio que trates de que la gente desplace mi publicación. Solo pensé que deberías saber eso. –

+0

No se trata de posdesplazamiento, sino de evitar errores y códigos peligrosos. Greetz GHad – GHad

+0

Se pueden evitar errores si las personas leen mi publicación completa (incluidas ambas adiciones). Si las personas simplemente cortan y pegan código sin pensar, entonces se merecen todo lo que obtienen. Los programadores cobran lo que hacen porque ejercitan sus cerebros ... espero. [continúa] –

13

Siempre se puede hacer:

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

depende de lo que entendemos por "eliminar"? Una matriz es una construcción de tamaño fijo; no puede cambiar la cantidad de elementos en ella. Por lo tanto, puede a) crear una matriz nueva, más corta, sin los elementos que no desea o b) asignar las entradas que no desea a algo que indique su estado 'vacío'; generalmente nulo si no está trabajando con primitivos.

En el primer caso, cree una lista de la matriz, elimine los elementos y cree una nueva matriz de la lista. Si el rendimiento es importante, repita la matriz asignando elementos que no deberían eliminarse a una lista y luego cree una nueva matriz de la lista. En el segundo caso, simplemente pase y asigne nulo a las entradas de la matriz.

5

Puede utilizar la biblioteca externa:

org.apache.commons.lang.ArrayUtils.remove(java.lang.Object[] array, int index) 

Está en proyecto Apache Commons Lang http://commons.apache.org/lang/

2

Comprendo que esto es un post muy antiguo, pero algunas de las respuestas aquí me ayudó, así que aquí está mi tuppence vale la pena!

Tuve problemas para conseguir que esto funcione durante bastante tiempo antes de pensar que la matriz en la que estoy escribiendo debe cambiar de tamaño, a menos que los cambios realizados en la ArrayList dejen inalterado el tamaño de la lista.

Si el ArrayList que está modificando extremos con elementos de mayor o menor de lo que se inició con la línea List.toArray() provocará una excepción, por lo que necesita algo así como List.toArray(new String[] {}) o List.toArray(new String[0]) con el fin de crear una matriz con el nuevo (correcto) tamaño.

Suena obvio ahora que lo sé. No es tan obvio para un novato de Android/Java que se está familiarizando con construcciones de código nuevas y desconocidas y no es obvio en algunas de las publicaciones anteriores aquí, así que quería dejar este punto claro para que nadie más se rascara la cabeza durante horas como yo !

+0

Sentí la necesidad de publicar esto, ya que a menudo uso fragmentos de código que no funcionan porque me perdí algo que otros programadores dan por sentado.GHad destacó el tamaño del Array que hizo que mi código funcionara (gracias por dejar eso en claro). Probar cosas es la manera de aprender, y si eso significa que merezco todo lo que obtengo por tomar el código de SO e intentar entender cómo y por qué funciona, entonces que así sea. Como aficionado no remunerado, ¡no soy el genio de Java que a algunos les gusta pensar que son! Afortunadamente, la mayoría de los colaboradores de SO responden preguntas para ayudar a otros a escribir un código mejor: ¡por eso, te mereces las gracias! – DDSports

1

Mi pequeña contribución a este problema.

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

}

+0

Esta es una muy buena respuesta, aunque su gran código de prueba lo hace parecer mucho más grande de lo que realmente es. La solución completa podría ser una matriz de una sola línea (suponiendo que use la misma matriz, que es lo que le gustaría hacer si estuviera trabajando tan cerca del metal que estaba utilizando matrices en lugar de colecciones). –

+0

gracias, lo escribí para que los lectores puedan ver un poco lo que sucede bajo el capó y probarlo, ahora lo veo de nuevo System.arraycopy (tmp1, 0, tmp2, 0, tmp2.length); puede eliminarse y reemplazarse por algo como por (i = 0; i <(arr.length - t); i ++) {tmp2 [i] = tmp1 [i]; } también puede crear un búfer de bytes y copiar 8 bytes a la vez en una máquina de 64 bits para obtener un rendimiento de copia adicional – Andre

5

Ver código de abajo

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

Una alternativa en Java 8:

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

Esta debería ser la respuesta aceptada. Aunque no es bonito teniendo en cuenta que otros lenguajes de programación pueden hacer esto con un código menos claro ... esto es lo mejor que Java tiene para ofrecer sin depender de otra biblioteca. – Jason

+3

Aunque es claro, esto va a ser increíblemente ineficiente en comparación con System.arraycopy. Probablemente no debería hacer esto en código real. –

4

Si necesita eliminar varios elementos de matriz sin convertirlo en List ni creando una matriz adicional, puede hacerlo en O (n) no depende del recuento de elementos para rem ove

Aquí, a es matriz inicial, int... r son índices ordenados distintas (posiciones) de elementos para eliminar:

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

pequeña prueba:

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] 

En su tarea, puede arsenal primera exploración para recoger posiciones de "a", luego llame al removeItems().

+0

Por favor, no hagas esto. Es confuso, lento y propenso a errores. Simplemente use System.arraycopy() en su lugar, aunque los puntos de bonificación por el hecho de que si va a manipular una matriz de esta manera debe hacer un seguimiento de la longitud. –

-2
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. 
+0

La pregunta sobre los objetos, no los números, y utiliza cadenas como un ejemplo. Para objetos y cadenas, sería necesario utilizar el método '.equals()' en lugar de '=='. –

-3

Uso:

list.removeAll(...); 
//post what char you need in the ... section 
+0

No dude en editar algunas partes. – LOL

0

copiará todos los elementos, excepto el uno con el índice 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)); 
      } 
1

Hay muchas respuestas aquí - el problema que veo es que no dijiste POR QUÉ estás usando una matriz en lugar de una colección, así que déjame sugerirte un par de razones y qué soluciones aplicarían (la mayoría de las soluciones ya han sido respondidas en otras preguntas aquí, así que no entraré en demasiado detalle) :

razón: Usted no sabe el paquete de colección existía o no confiaba en que

solución: Utilice una colección.

Si planea agregar/eliminar desde el medio, use una ListaEnlazada. Si está realmente preocupado por el tamaño o, a menudo, indexa justo en el medio de la colección, use una ArrayList. Ambos deberían tener operaciones de eliminación.

razón: Usted está preocupado por tamaño o quiere control sobre la asignación de memoria

solución: Utilice un ArrayList con un tamaño inicial específica.

Una ArrayList es simplemente una matriz que puede expandirse, pero no siempre tiene que hacerlo. Será muy inteligente agregar/eliminar elementos, pero nuevamente si está insertando/eliminando un LOTE desde el medio, use una Lista Vinculada.

razón: tiene una matriz que entra y una matriz de salir - por lo que desea operar en una serie

solución: Convertir a un ArrayList, elimine el elemento y convertirlo de nuevo

razón: usted piensa que puede escribir mejor código si lo hace usted mismo la solución

: no se puede, utilizar una matriz o lista enlazada.

razón: se trata de una tarea de clase y no se le permite o no tener acceso a las API de recolección por alguna razón

hipótesis: Es necesario la nueva matriz que es el "tamaño" correcto

solución: Escanee el conjunto de elementos coincidentes y cuéntelos. Cree una nueva matriz del tamaño correcto (tamaño original - número de coincidencias). use System.arraycopy varias veces para copiar cada grupo de elementos que desea conservar en su nueva matriz. Si se trata de una asignación de clase y no puede usar System.arraycopy, simplemente cópielos uno por uno a mano en un bucle, pero nunca haga esto en el código de producción porque es mucho más lento. (Estas soluciones son detalladas en otras respuestas)

razón: es necesario ejecutar el metal desnudo

hipótesis: No debe asignar espacio innecesariamente o tomar demasiado tiempo suposición

: Se realiza el seguimiento de la tamaño utilizado en la matriz (longitud) por separado porque de lo contrario tendrías que reasignar tu matriz para eliminar/insertar.

Un ejemplo de por qué es posible que desee hacer esto: una única matriz de primitivas (digamos valores int) está tomando una porción significativa de su ram, ¡como el 50%! Un ArrayList forzaría estos en una lista de punteros a objetos enteros que usarían algunas veces esa cantidad de memoria.

solución: itere sobre su matriz y siempre que encuentre un elemento para eliminar (llamémosle elemento n), use System.arraycopy para copiar la cola de la matriz sobre el elemento "eliminado" (Fuente y destino son la misma matriz) - es lo suficientemente inteligente como para hacer la copia en la dirección correcta para que la memoria no sobrescribe sí:

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

es probable que quiera ser más inteligente que esto si va a eliminar más de un elemento en un momento. Solo movería el área entre una "coincidencia" y la siguiente en lugar de toda la cola y, como siempre, evite mover cualquier trozo dos veces.

En este último caso, absolutamente debe hacer el trabajo usted mismo y usar el Sistema.arraycopy es realmente la única manera de hacerlo, ya que va a elegir la mejor manera posible de mover la memoria para la arquitectura de su computadora; debe ser mucho más rápido que cualquier código que pueda escribir usted mismo razonablemente.

Cuestiones relacionadas