2009-01-19 8 views
90

Tengo una matriz de objetos Foo. ¿Cómo elimino el segundo elemento de la matriz?Eliminar elemento de una matriz normal

Necesito algo similar a RemoveAt() pero para una matriz regular.

+0

Use '' System.Collections.ObjectModel.Collection . – abatishchev

+0

Para mi juego, fui con una estructura de datos "nulo en el índice". Básicamente, la matriz interna (buffer) es de tamaño estático, y en lugar de eliminar el índice y cambiar el tamaño de la matriz, simplemente hago que el índice sea nulo. Cuando necesito agregar un ítem, solo encuentro el primer índice no nulo y lo coloco allí. Funciona bastante bien, pero obviamente no para todo. – Krythic

Respuesta

148

Si no desea utilizar la lista:

var foos = new List<Foo>(array); 
foos.RemoveAt(index); 
return foos.ToArray(); 

Se puede probar este método de extensión que no he hecho probado:

public static T[] RemoveAt<T>(this T[] source, int index) 
{ 
    T[] dest = new T[source.Length - 1]; 
    if(index > 0) 
     Array.Copy(source, 0, dest, 0, index); 

    if(index < source.Length - 1) 
     Array.Copy(source, index + 1, dest, index, source.Length - index - 1); 

    return dest; 
} 

y utilizarlo como:

Foo[] bar = GetFoos(); 
bar = bar.RemoveAt(2); 
+6

El primer ejemplo dado en esta respuesta es mucho menos eficiente que el segundo. Requiere dos copias de matriz y un desplazamiento de todo después del índice en lugar de una copia de matriz selectiva. –

+1

+1 por supuesto, pero también podemos usar la lista O O Lista list = new List (GetFoos()); list.Remove (my_foo); list.RemoveAt (2); donde GetFoos() devolverá la matriz de Foos !!!! – shahjapan

+1

La primera línea dentro del método debe decir 'source.Length' en lugar de 'array.Length'. – Nelson

1

Así es como lo hice ...

public static ElementDefinitionImpl[] RemoveElementDefAt(
     ElementDefinition[] oldList, 
     int removeIndex 
    ) 
    { 
     ElementDefinitionImpl[] newElementDefList = new ElementDefinitionImpl[ oldList.Length - 1 ]; 

     int offset = 0; 
     for (int index = 0; index < oldList.Length; index++) 
     { 
      ElementDefinitionImpl elementDef = oldList[ index ] as ElementDefinitionImpl; 
      if (index == removeIndex) 
      { 
       // This is the one we want to remove, so we won't copy it. But 
       // every subsequent elementDef will by shifted down by one. 
       offset = -1; 
      } 
      else 
      { 
       newElementDefList[ index + offset ] = elementDef; 
      } 
     } 
     return newElementDefList; 
    } 
54

La naturaleza de las matrices es que su longitud es inmutable. No puede agregar ni eliminar ninguno de los elementos de la matriz.

Tendrá que crear una nueva matriz que sea un elemento más corto y copiar los elementos anteriores a la nueva matriz, excluyendo el elemento que desea eliminar.

Por lo tanto, probablemente sea mejor utilizar una lista en lugar de una matriz.

+3

Convierta la matriz en una lista 'List array = new List (arrayofmydatatype)' –

1

En una matriz normal, debe desplazar hacia abajo todas las entradas de la matriz por encima de 2 y luego cambiar su tamaño utilizando el método de Redimensionar. Es mejor que uses una ArrayList.

5

Aquí hay una versión anterior que tengo que funciona en la versión 1.0 del marco .NET y no necesita generi tipos de c.

public static Array RemoveAt(Array source, int index) 
{ 
    if (source == null) 
     throw new ArgumentNullException("source"); 

    if (0 > index || index >= source.Length) 
     throw new ArgumentOutOfRangeException("index", index, "index is outside the bounds of source array"); 

    Array dest = Array.CreateInstance(source.GetType().GetElementType(), source.Length - 1); 
    Array.Copy(source, 0, dest, 0, index); 
    Array.Copy(source, index + 1, dest, index, source.Length - index - 1); 

    return dest; 
} 

Esto se utiliza de esta manera:

class Program 
{ 
    static void Main(string[] args) 
    { 
     string[] x = new string[20]; 
     for (int i = 0; i < x.Length; i++) 
      x[i] = (i+1).ToString(); 

     string[] y = (string[])MyArrayFunctions.RemoveAt(x, 3); 

     for (int i = 0; i < y.Length; i++) 
      Console.WriteLine(y[i]); 
    } 
} 
43

utilizo este método para eliminar un elemento de una matriz objeto. En mi situación, mis arreglos son de poca longitud. Entonces, si tiene matrices grandes, es posible que necesite otra solución.

private int[] RemoveIndices(int[] IndicesArray, int RemoveAt) 
{ 
    int[] newIndicesArray = new int[IndicesArray.Length - 1]; 

    int i = 0; 
    int j = 0; 
    while (i < IndicesArray.Length) 
    { 
     if (i != RemoveAt) 
     { 
      newIndicesArray[j] = IndicesArray[i]; 
      j++; 
     } 

     i++; 
    } 

    return newIndicesArray; 
} 
+5

Personalmente, me gusta esta respuesta mejor que la respuesta aceptada. Debe ser igual de eficiente, y es mucho más fácil de leer. Puedo verlo y saber que es correcto. Tendría que probar el otro para asegurarme de que esas copias fueron escritas correctamente. – oillio

+0

Realmente es una pena que esta respuesta sea tan baja, cuando es mucho mejor que las dos anteriores. – Sepulchritude

3

No es exactamente la manera de hacer esto, pero si la situación es trivial y que valoran su tiempo, usted puede intentar esto para los tipos anulables.

Foos[index] = null 

y posterior comprobar las entradas nulas en su lógica ..

+0

Así es como lo hice para mi juego. Ir con almacenamientos intermedios anulables para las áreas que se cambian con mucha frecuencia. – Krythic

-4

Primer paso
es necesario convertir la matriz en una lista, se podría escribir un método de extensión como esto

// Convert An array of string to a list of string 
public static List<string> ConnvertArrayToList(this string [] array) { 

    // DECLARE a list of string and add all element of the array into it 

    List<string> myList = new List<string>(); 
    foreach(string s in array){ 
     myList.Add(s); 
    } 
    return myList; 
} 

Segundo paso
escribir un método de extensión para convertir de nuevo la lista en una matriz

// convert a list of string to an array 
public static string[] ConvertListToArray(this List<string> list) { 

    string[] array = new string[list.Capacity]; 
    array = list.Select(i => i.ToString()).ToArray(); 
    return array; 
} 

Últimos pasos
Escriba su último método, pero recuerde que debe retirar el elemento en el índice antes de convertir de nuevo a un conjunto como el código muestran

public static string[] removeAt(string[] array, int index) { 

    List<string> myList = array.ConnvertArrayToList(); 
    myList.RemoveAt(index); 
    return myList.ConvertListToArray(); 
} 

códigos ejemplos podrían encontrar en my blog, mantener el seguimiento.

+12

Esto es levemente loco considerando la existencia de '.ToArray()' y un constructor 'List ' que toma una secuencia existente ... – user7116

7

Esta es una manera de eliminar un elemento de la matriz, a partir de Net 3.5, sin copiar a otra matriz - utilizando la misma instancia de matriz con Array.Resize<T>:

public static void RemoveAt<T>(ref T[] arr, int index) 
{ 
    for (int a = index; a < arr.Length - 1; a++) 
    { 
     // moving elements downwards, to fill the gap at [index] 
     arr[a] = arr[a + 1]; 
    } 
    // finally, let's decrement Array's size by one 
    Array.Resize(ref arr, arr.Length - 1); 
} 
+0

"sin copiar a otra matriz" - según la documentación vinculada, Array.Resize en realidad * no * asigna una nueva matriz detrás de las escenas y copia los elementos de la matriz anterior a la nueva. Aún así, me gusta la concisión de esta solución. –

+0

Muy bueno y claro si está seguro de que es una matriz relativamente pequeña. – Darren

+0

Continuando el comentario de @JonSchneider, no es "la misma instancia de matriz". Por eso necesita usar 'ref' cuando llama al método' Resize'. La longitud de una instancia de matriz es fija e inmutable. –

2

Como de costumbre, llego tarde a la fiesta ...

Me gustaría agregar otra opción a la lista de soluciones interesantes ya presente. =)
Vería esto como una buena oportunidad para Extensions.

Referencia: http://msdn.microsoft.com/en-us/library/bb311042.aspx

Así, definimos una clase estática y en ella, nuestro método.
Después de eso, podemos usar nuestro método extendido de cualquier manera. =)

using System; 

namespace FunctionTesting { 

    // The class doesn't matter, as long as it's static 
    public static class SomeRandomClassWhoseNameDoesntMatter { 

     // Here's the actual method that extends arrays 
     public static T[] RemoveAt<T>(this T[] oArray, int idx) { 
      T[] nArray = new T[oArray.Length - 1]; 
      for(int i = 0; i < nArray.Length; ++i) { 
       nArray[i] = (i < idx) ? oArray[i] : oArray[i + 1]; 
      } 
      return nArray; 
     } 
    } 

    // Sample usage... 
    class Program { 
     static void Main(string[] args) { 
      string[] myStrArray = { "Zero", "One", "Two", "Three" }; 
      Console.WriteLine(String.Join(" ", myStrArray)); 
      myStrArray = myStrArray.RemoveAt(2); 
      Console.WriteLine(String.Join(" ", myStrArray)); 
      /* Output 
      * "Zero One Two Three" 
      * "Zero One Three" 
      */ 

      int[] myIntArray = { 0, 1, 2, 3 }; 
      Console.WriteLine(String.Join(" ", myIntArray)); 
      myIntArray = myIntArray.RemoveAt(2); 
      Console.WriteLine(String.Join(" ", myIntArray)); 
      /* Output 
      * "0 1 2 3" 
      * "0 1 3" 
      */ 
     } 
    } 
} 
31

LINQ solución de una línea:

myArray = myArray.Where((source, index) => index != 1).ToArray(); 

El 1 en ese ejemplo es el índice del elemento para eliminar - en este ejemplo, por la pregunta original, el segundo elemento (con 1 siendo el segundo elemento en la indexación de matriz basada en cero C#).

Un ejemplo más completo:

string[] myArray = { "a", "b", "c", "d", "e" }; 
int indexToRemove = 1; 
myArray = myArray.Where((source, index) => index != indexToRemove).ToArray(); 

Después de ejecutar que fragmento, el valor de myArray será { "a", "c", "d", "e" }.

+0

Para las áreas que requieren alto rendimiento/acceso frecuente, no se recomienda LINQ. – Krythic

+1

@Krythic Ese es un comentario justo. Se ejecuta miles de veces en un ciclo cerrado, el rendimiento de esta solución no es tan bueno como algunas de las otras soluciones altamente votadas en esta página: https://dotnetfiddle.net/z9Xkpn –

1
private int[] removeFromArray(int[] array, int id) 
    { 
     int difference = 0, currentValue=0; 
     //get new Array length 
     for (int i=0; i<array.Length; i++) 
     { 
      if (array[i]==id) 
      { 
       difference += 1; 
      } 
     } 
     //create new array 
     int[] newArray = new int[array.Length-difference]; 
     for (int i = 0; i < array.Length; i++) 
     { 
      if (array[i] != id) 
      { 
       newArray[currentValue] = array[i]; 
       currentValue += 1; 
      } 
     } 

     return newArray; 
    } 
0

Aquí hay una pequeña colección de métodos de ayuda que produje en función de algunas de las respuestas existentes. Se utiliza tanto las extensiones y los métodos estáticos con los parámetros de referencia para la máxima Idoneidad:

public static class Arr 
{ 
    public static int IndexOf<TElement>(this TElement[] Source, TElement Element) 
    { 
     for (var i = 0; i < Source.Length; i++) 
     { 
      if (Source[i].Equals(Element)) 
       return i; 
     } 

     return -1; 
    } 

    public static TElement[] Add<TElement>(ref TElement[] Source, params TElement[] Elements) 
    { 
     var OldLength = Source.Length; 
     Array.Resize(ref Source, OldLength + Elements.Length); 

     for (int j = 0, Count = Elements.Length; j < Count; j++) 
      Source[OldLength + j] = Elements[j]; 

     return Source; 
    } 

    public static TElement[] New<TElement>(params TElement[] Elements) 
    { 
     return Elements ?? new TElement[0]; 
    } 

    public static void Remove<TElement>(ref TElement[] Source, params TElement[] Elements) 
    { 
     foreach (var i in Elements) 
      RemoveAt(ref Source, Source.IndexOf(i)); 
    } 

    public static void RemoveAt<TElement>(ref TElement[] Source, int Index) 
    { 
     var Result = new TElement[Source.Length - 1]; 

     if (Index > 0) 
      Array.Copy(Source, 0, Result, 0, Index); 

     if (Index < Source.Length - 1) 
      Array.Copy(Source, Index + 1, Result, Index, Source.Length - Index - 1); 

     Source = Result; 
    } 
} 

En cuanto al rendimiento, es decente, pero probablemente podría mejorarse.Remove se basa en IndexOf y se crea una nueva matriz para cada elemento que desea eliminar llamando al RemoveAt.

IndexOf es el único método de extensión, ya que no necesita devolver la matriz original. New acepta múltiples elementos de algún tipo para producir una nueva matriz de dicho tipo. Todos los demás métodos deben aceptar el conjunto original como referencia, de modo que no sea necesario asignar el resultado después, como ocurre internamente.

Hubiera definido un método Merge para unir dos matrices; sin embargo, eso ya se puede lograr con el método Add al pasar una matriz real frente a múltiples elementos individuales. Por lo tanto, Add pueden usarse en las dos formas siguientes para unir dos conjuntos de elementos:

Arr.Add<string>(ref myArray, "A", "B", "C"); 

O

Arr.Add<string>(ref myArray, anotherArray); 
Cuestiones relacionadas