Ajouter un nouvel élément dans un tableau existant dans c # .net

134

Comment ajouter un nouvel élément dans un tableau de chaînes existant en C # .net?

J'ai besoin de préserver les données existantes.

A-Sharabiani
la source

Réponses:

121

J'utiliserais une liste si vous avez besoin d'un tableau de taille dynamique:

List<string> ls = new List<string>();
ls.Add("Hello");
Ed S.
la source
27
Et si nécessaire, faites ls.ToArray () à la fin
Narayana
2
Utiliser un autre mécanicien que celui posé dans la question n'est pas une réponse.
user11909
@ user2190035: Je ne sais pas d'où vous avez eu cette idée, et les 111 personnes qui ont voté pour le contre ne seraient pas d'accord avec vous. Si vous connaissez une meilleure façon d'étendre un tableau, alors postez-le. Je doute que votre réattribution et votre copie manuelle soient meilleures que l'utilisation d'une liste. Parfois, la réponse est «ne faites pas ça».
Ed S.
@ EdS La question était de savoir comment ajouter un élément à un tableau de chaînes existant , mais cette réponse n'a pas du tout de tableau, à la place, elle crée une nouvelle liste <>. Dans mon application, je ne peux pas changer le type en List <>, donc je dois redimensionner un tableau (faire une copie ...). La réponse d'Ali Ersöz m'a aidé.
user11909
@ user2190035: IEnumerable <T> .ToArray (). J'écris C # tous les jours et je n'ai jamais eu à redimensionner un tableau comme ça.
Ed S.
100

Cela pourrait être une solution;

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

Mais pour un tableau de taille dynamique, je préférerais aussi la liste.

Ali Ersöz
la source
@Konrad, cela préservera sûrement les données du tableau.
Ali Ersöz
1
cela ne convient pas pour plus de quelques instants. car la fonction 'Redimensionner' a une performance énorme. bug pour une ou deux fois, c'est très bien.
annonce le
53

Utilisation de LINQ:

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

J'aime l'utiliser car il s'agit d'une ligne unique et très pratique à intégrer dans une instruction switch, une simple instruction if ou à passer en argument.

ÉDITER:

Certaines personnes n'aiment pas new[] { newitem }car cela crée un petit tableau temporaire à un élément. Voici une version utilisant Enumerable.Repeatqui ne nécessite la création d'aucun objet (du moins pas en surface - les itérateurs .NET créent probablement un tas d'objets de machine d'état sous la table).

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

Et si vous êtes sûr que le tableau ne nulldémarre jamais , vous pouvez le simplifier comme suit:

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

Notez que si vous souhaitez ajouter des éléments à une collection ordonnée, il Lists'agit probablement de la structure de données souhaitée, pas d'un tableau pour commencer.

Stephen Chung
la source
1
Très joli +1. J'ai un code similaire en tant que méthode d'extension générique. J'ai inclus le code dans cette réponse: stackoverflow.com/a/11035286/673545
dblood
Ceci est très utile lors de la recherche de "comment ajouter à un tableau dans une ligne de code en c #" - j'espère que ce commentaire sera suffisant pour le retrouver la prochaine fois.
gary
28

Très vieille question, mais je voulais toujours ajouter ceci.

Si vous recherchez un one-liner, vous pouvez utiliser le code ci-dessous. Il combine le constructeur de liste qui accepte un énumérable et la «nouvelle» syntaxe d'initialisation (depuis la question soulevée).

myArray = new List<string>(myArray) { "add this" }.ToArray();
Grimace de désespoir
la source
27

Les tableaux en C # sont immuables , par exemple string[], int[]. Cela signifie que vous ne pouvez pas les redimensionner. Vous devez créer un tout nouveau tableau.

Voici le code pour 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;
    }
}

Comme vous pouvez le voir, il crée un nouveau tableau avec la nouvelle taille, copie le contenu du tableau source et définit la référence au nouveau tableau. L'indice pour cela est le mot-clé ref pour le premier paramètre.

Il existe des listes qui peuvent allouer dynamiquement de nouveaux emplacements pour de nouveaux éléments. Il s'agit par exemple de List <T> . Ceux-ci contiennent des tableaux immuables et les redimensionnent si nécessaire (List <T> n'est pas une implémentation de liste chaînée!).ArrayList est la même chose sans Generics (avec un tableau Object ).

LinkedList <T> est une véritable implémentation de liste chaînée. Malheureusement, vous pouvez ajouter uniquement des éléments LinkListNode <T> à la liste, vous devez donc encapsuler vos propres éléments de liste dans ce type de nœud. Je pense que son utilisation est rare.

artur02
la source
Je pense que vous avez voulu dire Array.Copy
user123456
2
Seule réponse qui fournit des informations sur les raisons pour lesquelles ce n'est pas possible et ne suggère pas seulement d'utiliser une liste ...
Gilad Green
Je pense que l' Aray.Resizeon peut redimensionner un tableau sans perdre son contenu. 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";
tmanie
la source
7

Vous pouvez développer la réponse fournie par @Stephen Chung en utilisant sa logique basée sur LINQ pour créer une méthode d'extension à l'aide d'un type générique.

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

}

Vous pouvez alors l'appeler directement sur le tableau comme ceci.

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

Certes, la méthode AddRangeToArray () semble un peu exagérée puisque vous avez la même fonctionnalité avec Concat () mais de cette façon, le code de fin peut "travailler" avec le tableau directement par opposition à ceci:

options = options.Concat(new string[] { "one", "two", "three" }).ToArray();
dblood
la source
Merci, cela a été très utile, j'ai ajouté une option pour supprimer un élément (j'espère que cela vous convient).
Tal Segal
@TalSegal vous êtes les bienvenus, mon plaisir. Utilisez le code comme bon vous semble!
dblood
6

Il est préférable de garder Array immuable et de taille fixe.

vous pouvez simuler Addpar Extension MethodetIEnumerable.Concat()

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

si vous travaillez beaucoup avec des tableaux et non des listes pour une raison quelconque, cette méthode générique générique de retour typé Addpourrait vous aider

    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
la source
4

Toutes les réponses proposées font la même chose que ce qu'elles disent vouloir éviter, en créant un nouveau tableau et en y ajoutant une nouvelle entrée uniquement avec une perte de plus de frais généraux. LINQ n'est pas magique, la liste de T est un tableau avec un espace tampon avec un peu d'espace supplémentaire pour éviter de redimensionner le tableau interne lorsque des éléments sont ajoutés.

Toutes les abstractions doivent résoudre le même problème, créer un tableau sans emplacements vides contenant toutes les valeurs et les renvoyer.

Si vous avez besoin de flexibilité et que vous pouvez créer une liste suffisamment grande que vous pouvez utiliser pour passer, faites-le. Sinon, utilisez un tableau et partagez cet objet thread-safe. En outre, le nouveau Span permet de partager des données sans avoir à copier les listes.

Pour répondre à la question:

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

Donc, si vous avez un tableau existant, ma solution rapide sera

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

Maintenant, remplacez simplement le tableau d'origine par le nouveau

originalArray = tempList.ToArray();
Adi_Pithwa
la source
Résolu ma solution
praguan
3

Une nouvelle Append<TSource>méthode a été ajoutée àIEnumerable<TSource> depuis .NET Framework 4.7.1 et .NET Core 1.0.

Voici comment l'utiliser:

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

Notez que si vous souhaitez ajouter l'élément au début du tableau, vous pouvez utiliser la nouvelle Prepend<TSource>méthode à la place.

0xced
la source
2

L'utilisation d'une liste serait votre meilleure option pour la gestion de la mémoire.

Axxelsian
la source
2

Qu'en est-il de l'utilisation d'une méthode d'extension? Par exemple:

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

par exemple:

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

Notez que cela imite ce comportement de l'extension Uniion de Linq (utilisée pour combiner deux tableaux en un nouveau) et nécessitait que la bibliothèque Linq fonctionne.

William
la source
1

Je suis d'accord avec Ed. C # ne facilite pas cela comme le fait VB avec ReDim Preserve. Sans collection, vous devrez copier le tableau dans un plus grand.

harpo
la source
2
Dieu merci! ReDim est incroyablement lent en cas d'abus. =)
Ed S.
ReDim Preservecopie simplement le tableau dans un plus lager. Il n'y a pas de redimensionnement miraculeux du tableau.
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
la source
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
la source
0

Malheureusement, l'utilisation d'une liste ne fonctionnera pas dans toutes les situations. Une liste et un tableau sont en fait différents et ne sont pas interchangeables à 100%. Cela dépendrait des circonstances si ce serait une solution acceptable.

POT
la source
0

Puisque cette question n'est pas satisfaite de la réponse fournie, j'aimerais ajouter cette réponse :)

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
la source