Agregue un nuevo elemento en la matriz existente en c # .net

134

¿Cómo agregar un nuevo elemento en una matriz de cadenas existente en C # .net?

Necesito preservar los datos existentes.

A-Sharabiani
fuente

Respuestas:

121

Usaría una Lista si necesita una matriz de tamaño dinámico:

List<string> ls = new List<string>();
ls.Add("Hello");
Ed S.
fuente
27
Y si es necesario, haga ls.ToArray () al final
Narayana
2
Usar otra mecánica diferente a la que se hizo en la pregunta no es una respuesta.
user11909
@ user2190035: No estoy seguro de dónde sacaste esa idea, y las 111 personas que votaron no estarían de acuerdo contigo. Si conoce una mejor manera de expandir una matriz, publíquela por todos los medios. Sin embargo, dudo que su reasignación y copia manual sean mejores que usar una Lista. A veces la respuesta es "no hagas eso".
Ed S.
@ EdS. La pregunta era cómo agregar un elemento a una matriz de cadenas existente , pero esta respuesta no tiene ninguna matriz, sino que crea una nueva Lista <>. En mi aplicación, no puedo cambiar el tipo a Lista <>, por lo tanto, tengo que cambiar el tamaño de una matriz (hacer una copia ...). La respuesta de Ali Ersöz me ayudó.
user11909
@ user2190035: IEnumerable <T> .ToArray (). Escribo C # todos los días y nunca he tenido que cambiar el tamaño de una matriz como esa.
Ed S.
100

Eso podría ser una solución;

Array.Resize(ref array, newsize);
array[newsize - 1] = "newvalue"

Pero para una matriz de tamaño dinámico, también preferiría la lista.

Ali Ersöz
fuente
@Konrad, eso seguramente preservará los datos en la matriz.
Ali Ersöz
1
Esto no es adecuado para invocar más de unas pocas veces. porque la función 'Cambiar tamaño' tiene un gran rendimiento. error por una o dos veces, esto es muy bueno.
anuncio del
53

Usando LINQ:

arr = (arr ?? Enumerable.Empty<string>()).Concat(new[] { newitem }).ToArray();

Me gusta usar esto, ya que es de una sola línea y muy conveniente para incrustar en una declaración de cambio, una simple declaración if o pasar como argumento.

EDITAR:

A algunas personas no les gusta new[] { newitem }porque crea una pequeña matriz temporal de un solo elemento. Aquí hay una versión Enumerable.Repeatque no requiere la creación de ningún objeto (al menos no en la superficie; los iteradores de .NET probablemente crean un montón de objetos de máquina de estado debajo de la tabla).

arr = (arr ?? Enumerable.Empty<string>()).Concat(Enumerable.Repeat(newitem,1)).ToArray();

Y si está seguro de que la matriz nunca nullcomenzará, puede simplificarla para:

arr.Concat(Enumerable.Repeat(newitem,1)).ToArray();

Tenga en cuenta que si desea agregar elementos a una colección ordenada, Listprobablemente sea la estructura de datos que desea, no una matriz para comenzar.

Stephen Chung
fuente
1
Muy agradable +1. Tengo un código similar como un método de extensión genérico. He incluido el código en esta respuesta: stackoverflow.com/a/11035286/673545
dblood
Esto es muy útil al encontrar "cómo agregar a una matriz en una línea de código en c #". Esperemos que este comentario sea suficiente para encontrarlo nuevamente la próxima vez.
Gary
28

Pregunta muy antigua, pero todavía quería agregar esto.

Si está buscando una línea, puede usar el siguiente código. Combina el constructor de la lista que acepta una sintaxis de inicializador enumerable y la "nueva" (desde la pregunta planteada).

myArray = new List<string>(myArray) { "add this" }.ToArray();
Mueca de desesperación
fuente
27

Las matrices en C # son inmutables , por ejemplo string[], int[]. Eso significa que no puede cambiar su tamaño. Necesita crear una nueva gama.

Aquí está el código para Array.Resize :

public static void Resize<T>(ref T[] array, int newSize)
{
    if (newSize < 0)
    {
        throw new ArgumentOutOfRangeException("newSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
    }
    T[] sourceArray = array;
    if (sourceArray == null)
    {
        array = new T[newSize];
    }
    else if (sourceArray.Length != newSize)
    {
        T[] destinationArray = new T[newSize];
        Copy(sourceArray, 0, destinationArray, 0, (sourceArray.Length > newSize) ? newSize : sourceArray.Length);
        array = destinationArray;
    }
}

Como puede ver, crea una nueva matriz con el nuevo tamaño, copia el contenido de la matriz de origen y establece la referencia a la nueva matriz. La sugerencia para esto es la palabra clave ref para el primer parámetro.

Hay listas que pueden asignar dinámicamente nuevos espacios para nuevos elementos. Esto es, por ejemplo, Lista <T> . Estos contienen matrices inmutables y los redimensionan cuando es necesario (¡List <T> no es una implementación de lista vinculada!). ArrayList es lo mismo sin Generics (con Object array).

LinkedList <T> es una implementación real de la lista vinculada. Desafortunadamente, puede agregar solo elementos LinkListNode <T> a la lista, por lo que debe ajustar sus propios elementos de lista en este tipo de nodo. Creo que su uso es poco común.

artur02
fuente
Creo que te refieres a Array.Copy
user123456
2
La única respuesta que proporciona información sobre por qué no es posible y no solo sugiere usar una lista ...
Gilad Green
Creo que Aray.Resizepuede cambiar el tamaño de una matriz sin perder su contenido. docs.microsoft.com/en-us/dotnet/api/…
AbdelAziz AbdelLatef
25
 Array.Resize(ref youur_array_name, your_array_name.Length + 1);
 your_array_name[your_array_name.Length - 1] = "new item";
tmania
fuente
7

Puede ampliar la respuesta proporcionada por @Stephen Chung utilizando su lógica basada en LINQ para crear un método de extensión utilizando un tipo genérico.

public static class CollectionHelper
{
    public static IEnumerable<T> Add<T>(this IEnumerable<T> sequence, T item)
    {
        return (sequence ?? Enumerable.Empty<T>()).Concat(new[] { item });
    }

    public static T[] AddRangeToArray<T>(this T[] sequence, T[] items)
    {
        return (sequence ?? Enumerable.Empty<T>()).Concat(items).ToArray();
    }

    public static T[] AddToArray<T>(this T[] sequence, T item)
    {
        return Add(sequence, item).ToArray();
    }

}

Luego puede llamarlo directamente en la matriz de esta manera.

    public void AddToArray(string[] options)
    {
        // Add one item
        options = options.AddToArray("New Item");

        // Add a 
        options = options.AddRangeToArray(new string[] { "one", "two", "three" });

        // Do stuff...
    }

Es cierto que el método AddRangeToArray () parece un poco exagerado ya que tiene la misma funcionalidad con Concat (), pero de esta manera el código final puede "funcionar" directamente con la matriz en lugar de esto:

options = options.Concat(new string[] { "one", "two", "three" }).ToArray();
dblood
fuente
Gracias, esto fue muy útil, he agregado una opción para eliminar un elemento (espero que esté bien con usted).
Tal Segal
@TalSegal de nada, un placer. ¡Usa el código como mejor te parezca!
dblood
6

Es mejor mantener la matriz inmutable y de tamaño fijo.

puedes simular Addpor Extension MethodyIEnumerable.Concat()

public static class ArrayExtensions
    {
        public static string[] Add(this string[] array, string item)
        {
            return array.Concat(new[] {item}).ToArray();
        }
    }
Soren
fuente
5

si está trabajando mucho con matrices y no con listas por alguna razón, este método genérico de devolución con tipo genérico Addpodría ayudarlo

    public static T[] Add<T>(T[] array, T item)
    {
        T[] returnarray = new T[array.Length + 1];
        for (int i = 0; i < array.Length; i++)
        {
            returnarray[i] = array[i];
        }
        returnarray[array.Length] = item;
        return returnarray;
    }
stackuser83
fuente
4

Todas las respuestas propuestas hacen lo mismo que dicen que les gustaría evitar, crean una nueva matriz y agregan una nueva entrada solo con la pérdida de más sobrecarga. LINQ no es mágico, la lista de T es una matriz con un espacio de búfer con algo de espacio adicional para evitar cambiar el tamaño de la matriz interna cuando se agregan elementos.

Todas las abstracciones tienen que resolver el mismo problema, crear una matriz sin espacios vacíos que contengan todos los valores y los devuelvan.

Si necesita la flexibilidad y puede crear una lista lo suficientemente grande que puede usar para pasar, hágalo. de lo contrario, use una matriz y comparta ese objeto seguro para subprocesos. Además, el nuevo Span ayuda a compartir datos sin tener que copiar las listas.

Para responder la pregunta:

Array.Resize(ref myArray, myArray.Length + 1);
data[myArray.Length - 1] = Value;
Walter Vehoeven
fuente
4

Entonces, si tiene una matriz existente, mi solución rápida será

var tempList = originalArray.ToList();
tempList.Add(newitem);

Ahora solo reemplace la matriz original con la nueva

originalArray = tempList.ToArray();
Adi_Pithwa
fuente
Resolvió
3

Se Append<TSource>ha agregado un nuevo método IEnumerable<TSource>desde .NET Framework 4.7.1 y .NET Core 1.0.

Aquí está cómo usarlo:

var numbers = new [] { "one", "two", "three" };
numbers = numbers.Append("four").ToArray();
Console.WriteLine(string.Join(", ", numbers)); // one, two, three, four

Tenga en cuenta que si desea agregar el elemento al comienzo de la matriz, puede utilizar el nuevo Prepend<TSource>método.

0xced
fuente
2

Usar una lista sería su mejor opción para administrar la memoria.

Axxelsian
fuente
2

¿Qué pasa con el uso de un método de extensión? Por ejemplo:

public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> source, TSource item)
{
    return source.Union(new TSource[] { item });
}

por ejemplo:

string[] sourceArray = new []
{
    "foo",
    "bar"
}
string additionalItem = "foobar";
string result = sourceArray.Union(additionalItem);

Tenga en cuenta que esto imita este comportamiento de la extensión Uniion de Linq (utilizada para combinar dos matrices en una nueva), y requiere la biblioteca Linq para funcionar.

Guillermo
fuente
1

Estoy de acuerdo con Ed. C # no lo hace tan fácil como lo hace VB con ReDim Preserve. Sin una colección, tendrá que copiar la matriz en una más grande.

harpo
fuente
2
¡Gracias a Dios! ReDim es increíblemente lento cuando se abusa de él. =)
Ed S.
ReDim Preservesimplemente copia la matriz en una lager. No hay cambio milagroso de matriz.
Olivier Jacot-Descombes
1
string str = "string ";
List<string> li_str = new List<string>();
    for (int k = 0; k < 100; i++ )
         li_str.Add(str+k.ToString());
string[] arr_str = li_str.ToArray();
Gia Duong Duc Minh
fuente
0
private static string[] GetMergedArray(string[] originalArray, string[] newArray)
    {
        int startIndexForNewArray = originalArray.Length;
        Array.Resize<string>(ref originalArray, originalArray.Length + newArray.Length);
        newArray.CopyTo(originalArray, startIndexForNewArray);
        return originalArray;
    }
Dave Blake
fuente
0

Desafortunadamente, usar una lista no funcionará en todas las situaciones. Una lista y una matriz son realmente diferentes y no son 100% intercambiables. Dependería de las circunstancias si esto fuera una solución aceptable.

TARRO
fuente
0

Dado que esta pregunta no está satisfecha con la respuesta proporcionada, me gustaría agregar esta respuesta :)

public class CustomArrayList<T> 
 {  
   private T[] arr;  private int count;  

public int Count  
  {   
    get   
      {    
        return this.count;   
      }  
   }  
 private const int INITIAL_CAPACITY = 4;  

 public CustomArrayList(int capacity = INITIAL_CAPACITY) 
 {  
    this.arr = new T[capacity];   this.count = 0; 
  } 

 public void Add(T item) 
  {  
    GrowIfArrIsFull();  
   this.arr[this.count] = item;  this.count++; 
  }  

public void Insert(int index, T item) 
{  
 if (index > this.count || index < 0)  
    {   
      throw new IndexOutOfRangeException(    "Invalid index: " + index);  
     }  
     GrowIfArrIsFull();  
     Array.Copy(this.arr, index,   this.arr, index + 1, this.count - index);          
    this.arr[index] = item;  this.count++; }  

    private void GrowIfArrIsFull() 
    {  
    if (this.count + 1 > this.arr.Length)  
    {   
      T[] extendedArr = new T[this.arr.Length * 2];  
      Array.Copy(this.arr, extendedArr, this.count);  
      this.arr = extendedArr;  
    } 
  }
 }
}
Saif
fuente