C # .net içindeki mevcut diziye yeni öğe ekle


134

C # .net'te var olan dizge dizisine yeni öğe nasıl eklenir?

Mevcut verileri korumam gerekiyor.

Yanıtlar:


121

Dinamik olarak boyutlandırılmış bir diziye ihtiyacınız varsa bir Liste kullanırım:

List<string> ls = new List<string>();
ls.Add("Hello");

27
Ve gerekirse, sonunda ls.ToArray () yapın
Narayana

2
Soruda sorulandan başka bir mekanik kullanmak bir cevap değildir.
user11909

@ user2190035: Bu fikri nereden edindiğinizden emin değilim ve oy veren 111 kişi sizinle aynı fikirde olmayacaktır. Bir diziyi genişletmenin daha iyi bir yolunu biliyorsanız, o zaman kesinlikle gönderin. Yeniden ayırmanızın ve manuel kopyanızın bir Liste kullanmaktan daha iyi olacağından şüpheliyim. Bazen cevap "bunu yapma" olur.
Ed S.

@ EdS. Soru şuydu, var olan bir dizge dizisine bir öğe nasıl eklenir , ancak bu yanıtın hiç dizisi yoktur, bunun yerine yeni bir Liste <> oluşturur. Uygulamamda, türü Liste <> olarak değiştiremiyorum, bu nedenle bir diziyi yeniden boyutlandırmam gerekiyor (bir kopya yapıyorum ...). Ali Ersöz'ün cevabı bana yardımcı oldu.
user11909

@ user2190035: IEnumerable <T> .ToArray (). Her gün C # yazıyorum ve hiç böyle bir diziyi yeniden boyutlandırmak zorunda kalmadım.
Ed S.

100

Bu bir çözüm olabilir;

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

Ancak dinamik boyutlu diziler için de listeyi tercih ederim.


@Konrad, bu kesinlikle dizideki verileri koruyacak.
Ali Ersöz

1
bu, birkaç kez çağırmaktan daha fazlası için uygun değildir. çünkü "Yeniden Boyutlandır" işlevi büyük bir performansa sahiptir. bir veya iki kez hata, bu çok iyi.
reklam

53

LINQ kullanarak:

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

Bunu tek satırlık olduğu ve bir switch ifadesine, basit bir if-ifadesine veya argüman olarak geçirmeye çok uygun olduğu için kullanmayı seviyorum.

DÜZENLE:

Bazı insanlar new[] { newitem }, küçük, tek öğeli, geçici bir dizi oluşturduğu için sevmez . Burada, Enumerable.Repeatherhangi bir nesne oluşturmayı gerektirmeyen bir sürüm bulunmaktadır (en azından yüzeyde değil - .NET yineleyicileri muhtemelen tablonun altında bir grup durum makinesi nesnesi oluşturur).

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

Ve dizinin asla nullbaşlamayacağından eminseniz, onu şu şekilde basitleştirebilirsiniz:

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

Sıralı bir koleksiyona öğe eklemek istiyorsanız List, muhtemelen başlamak için bir dizi değil, istediğiniz veri yapısı olduğuna dikkat edin.


1
Çok güzel +1. Genel bir uzantı yöntemi olarak benzer bir kodum var. Kodu bu yanıta
ekledim

Bu, "c # kodunun bir satırındaki bir diziye nasıl ekleneceğini" ararken bulduğumuz çok yararlıdır - umarım bu yorum bir dahaki sefere onu tekrar bulmak için yeterlidir.
gary

28

Çok eski bir soru, ama yine de bunu eklemek istedim.

Tek satırlık bir ürün arıyorsanız, aşağıdaki kodu kullanabilirsiniz. Bir numaralandırılabilir ve "yeni" (soru ortaya çıktığından beri) başlatıcı sözdizimini kabul eden liste yapıcısını birleştirir.

myArray = new List<string>(myArray) { "add this" }.ToArray();

27

C # dizileri değişmezdir , örneğin string[],int[] . Bu, onları yeniden boyutlandıramayacağınız anlamına gelir. Yepyeni bir dizi oluşturmanız gerekiyor.

İşte Array.Resize kodu :

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

Gördüğünüz gibi, yeni boyutta yeni bir dizi oluşturur, kaynak dizinin içeriğini kopyalar ve başvuruyu yeni diziye ayarlar. Bunun ipucu, ref , birinci parametrenin anahtar kelimesidir.

Yeni öğeler için dinamik olarak yeni yuvalar tahsis edebilen listeler vardır . Bu, örneğin Liste <T> . Bunlar değişmez diziler içerir ve gerektiğinde bunları yeniden boyutlandırır (List <T> bağlantılı bir liste uygulaması değildir!). ArrayList , Generics olmadan ( Object dizisi ile) aynı şeydir .

LinkedList <T> gerçek bir bağlantılı liste uygulamasıdır. Maalesef listeye yalnızca LinkListNode <T> öğeleri ekleyebilirsiniz, bu nedenle kendi liste öğelerinizi bu düğüm türüne sarmanız gerekir. Sanırım kullanımı nadirdir.


Sanırım Array.Copy demek
istediniz

2
Sadece bunun neden mümkün olmadığına dair bazı bilgiler veren ve sadece bir liste kullanmayı önermeyen cevap ...
Gilad Green

Aray.ResizeBir diziyi içeriğini kaybetmeden yeniden boyutlandırabileceğine inanıyorum . 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";

7

Genel bir tür kullanarak bir uzantı yöntemi oluşturmak için LINQ tabanlı mantığını kullanarak @Stephen Chung tarafından sağlanan yanıtı genişletebilirsiniz.

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

}

Daha sonra bu şekilde doğrudan dizi üzerinden çağırabilirsiniz.

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

Kuşkusuz, AddRangeToArray () yöntemi, Concat () ile aynı işlevselliğe sahip olduğunuz için biraz abartılı görünmektedir, ancak bu şekilde, bitiş kodu, bunun tersine doğrudan dizi ile "çalışabilir":

options = options.Concat(new string[] { "one", "two", "three" }).ToArray();

Teşekkürler, Bu çok yardımcı oldu, bir öğeyi kaldırmak için bir seçenek ekledim (umarım bu senin için sorun olmaz).
Tal Segal

@TalSegal hoş geldiniz, benim için zevk. Kodu uygun gördüğünüz gibi kullanın!
dblood

6

Array'i değişmez ve sabit boyutta tutmak daha iyidir.

Eğer simüle edebilirsiniz Addtarafından Extension MethodveIEnumerable.Concat()

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

5

Dizilerle çok çalışıyorsanız ve herhangi bir nedenle listelerle çalışmıyorsanız, bu genel türdeki genel dönüş yöntemi Addyardımcı olabilir

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

4

Önerilen tüm yanıtlar, kaçınmak istediklerini söyledikleri şeyle aynı şeyi yapar, yeni bir dizi oluşturur ve ona yalnızca daha fazla ek yük kaybederek yeni bir giriş ekler. LINQ sihirli değildir, T listesi, öğeler eklendiğinde iç dizinin yeniden boyutlandırılmasını önlemek için fazladan boşluk içeren bir arabellek alanına sahip bir dizidir.

Tüm soyutlamaların aynı sorunu çözmesi, tüm değerleri tutan boş yuvaları olmayan bir dizi oluşturması ve bunları döndürmesi gerekir.

Esnekliğe ihtiyacınız varsa, geçmek için kullanabileceğiniz yeterince büyük bir liste oluşturabilir, sonra bunu yapın. başka bir dizi kullanır ve bu iş parçacığı güvenli nesneyi paylaşır. Ayrıca yeni Span, listeleri kopyalamak zorunda kalmadan verilerin paylaşılmasına yardımcı olur.

Soruyu cevaplamak için:

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

4

Dolayısıyla, mevcut bir diziniz varsa, benim hızlı düzeltmem

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

Şimdi orijinal diziyi yenisiyle değiştirin

originalArray = tempList.ToArray();

Benim çözüm çözüldü
praguan

3

Yeni bir Append<TSource>yöntem eklendiIEnumerable<TSource>.NET Framework 4.7.1 ve .NET Core 1.0'dan beri .

İşte nasıl kullanılacağı:

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

Öğeyi dizinin başına eklemek istiyorsanız, Prepend<TSource>bunun yerine yeni yöntemi kullanabileceğinizi unutmayın .


2

Bir liste kullanmak, bellek yönetimi için en iyi seçeneğiniz olacaktır.


2

Bir uzatma yöntemi kullanmaya ne dersiniz? Örneğin:

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

Örneğin:

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

Bunun Linq'in Uniion uzantısının (iki diziyi yeni bir dizide birleştirmek için kullanılır) bu davranışını taklit ettiğini ve Linq kitaplığının çalışması gerektiğini unutmayın.


1

Ed'e katılıyorum. C #, VB'nin ReDim Preserve ile yaptığı gibi bunu kolaylaştırmaz. Bir koleksiyon olmadan, diziyi daha büyük bir diziye kopyalamanız gerekir.


2
Tanrıya şükür! ReDim, istismar edildiğinde inanılmaz derecede yavaştır. =)
Ed S.

ReDim Preservebasitçe diziyi daha büyük bir diziye kopyalar. Mucizevi bir dizi yeniden boyutlandırma yoktur.
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();

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


0

Maalesef bir liste kullanmak her durumda işe yaramayacaktır. Bir liste ve bir dizi aslında farklıdır ve% 100 birbirinin yerine geçemez. Bunun etrafta kabul edilebilir bir çalışma olması koşullara bağlı olacaktır.


0

Bu soru verilen cevaptan memnun olmadığından, bu cevabı eklemek istiyorum :)

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;  
    } 
  }
 }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.