Додайте новий елемент у існуючий масив у c # .net


134

Як додати новий елемент у існуючий масив рядків у C # .net?

Мені потрібно зберегти наявні дані.

Відповіді:


121

Я використовую список, якщо вам потрібен масив з динамічним розміром:

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

27
І якщо потрібно, зробіть ls.ToArray () наприкінці
Narayana

2
Використання іншого механіка, ніж задано у запитанні, не є відповіддю.
user11909

@ user2190035: Не впевнений, звідки ви взяли таку ідею, і 111 людей, які проголосували, не згодні з вами. Якщо ви знаєте кращий спосіб розширити масив, то будь-якими способами опублікуйте його. Я сумніваюся, що ваш перерозподіл та копія вручну будуть кращими, ніж використання списку. Іноді відповідь - "не роби цього".
Ред С.

@ EdS. Питання полягало в тому, як додати елемент до існуючого масиву рядків , але ця відповідь взагалі не має масиву, натомість створює новий Список <>. У своїй програмі я не можу змінити тип на Список <>, тому мені доведеться змінити розмір масиву (зробити копію ...). Відповідь Алі Ержоса мені допомогла.
користувач11909

@ user2190035: Безліч <T> .ToArray (). Я пишу C # щодня, і мені ніколи не доводилося змінювати розмір масиву, як це.
Ед С.

100

Це може бути рішенням;

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

Але для масиву з динамічним розміром я також вважаю за краще список.


@Konrad, це, безумовно, збереже дані в масиві.
Алі Ерьоз

1
це не підходить для виклику більше декількох разів. тому що функція 'Resize' має величезну продуктивність. помилка один-два рази, це дуже добре.
оголошення

53

Використання LINQ:

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

Мені подобається використовувати це, оскільки це однолінійне і дуже зручно вставляти в оператор переключення, простий if-оператор або передавати як аргумент.

Редагувати:

Деяким людям це не подобається, new[] { newitem }оскільки це створює невеликий, однопозиційний тимчасовий масив. Ось версія з використанням Enumerable.Repeat, яка не потребує створення жодного об'єкта (принаймні, не на поверхні - .NET ітератори, ймовірно, створюють купу об'єктів машинного стану під таблицею).

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

І якщо ви впевнені, що масив ніколи не nullпочинається, ви можете спростити його до:

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

Зауважте, що якщо ви хочете додати елементи до впорядкованої колекції, Listце, мабуть, структура даних, яку ви хочете, а не масив для початку.


1
Дуже приємно +1. У мене схожий код як на загальний метод розширення. Я включив код у відповідь: stackoverflow.com/a/11035286/673545
dblood

Це дуже корисно, коли він шукав "як додати масив в одному рядку коду в c #" - сподіваємось, цього коментаря достатньо, щоб знову його знайти наступного разу.
gary

28

Дуже давнє запитання, але все ж хотілося додати це.

Якщо ви шукаєте однолінійку, можете скористатися наведеним нижче кодом. Він поєднує конструктор списку, який приймає численні та "новий" (з моменту виникнення питання) ініціалізатор синтаксису.

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

27

Масиви в C # є незмінними , наприклад string[], int[]. Це означає, що ви не можете змінити їх розмір. Потрібно створити абсолютно новий масив.

Ось код для 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;
    }
}

Як ви бачите, він створює новий масив з новим розміром, копіює вміст вихідного масиву та встановлює посилання на новий масив. Підказка для цього - ключове слово ref для першого параметра.

Є списки, які можуть динамічно виділяти нові слоти для нових елементів. Це, наприклад, Список <T> . Вони містять незмінні масиви та змінюють їх розмір за потреби (Список <T> не є пов'язаним виконанням списку!). ArrayList - те саме, що не має Generics (з масивом Object ).

LinkedList <T> - реальна реалізація пов'язаного списку. На жаль, ви можете додати до списку лише елементи LinkListNode <T>, тож вам потрібно перетворити власні елементи списку в цей тип вузла. Я думаю, його використання є рідкістю.


Думаю, ви мали на увазі Array.Copy
user123456

2
Єдина відповідь, яка надає деяку інформацію, чому це неможливо і не просто пропонує скористатися списком ...
Gilad Green

Я вважаю, що ви Aray.Resizeможете змінити розмір масиву, не втрачаючи його вміст. 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

Ви можете розширити відповідь, надану @Stephen Chung, використовуючи свою логіку на основі LINQ, щоб створити метод розширення, використовуючи загальний тип.

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

}

Потім ви можете зателефонувати безпосередньо на масив.

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

Правда, метод AddRangeToArray () здається трохи надмірним, оскільки у вас однаковий функціонал з Concat (), але таким чином кінцевий код може "працювати" з масивом безпосередньо на відміну від цього:

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

Дякую, це було дуже корисно, я додав можливість видалити предмет (сподіваюся, що з вами це нормально).
Таль Сегал

@TalSegal ласкаво просимо, моє задоволення. Використовуйте код, як вважаєте за потрібне!
dblood

6

Краще зберігати масив незмінним і фіксованим розміром.

ви можете імітувати Addза допомогою Extension MethodіIEnumerable.Concat()

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

5

якщо ви багато працюєте з масивами, а не перераховуєте їх з певних причин, цей загальний набраний загальний метод повернення Addможе допомогти

    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

Усі запропоновані відповіді виконують те саме, що вони кажуть, що хотіли б уникнути, створюючи новий масив і додаючи новий запис до нього, лише із втраченими накладними витратами. LINQ не є магічним, список T - це масив з буферним простором з деяким додатковим простором, щоб уникнути зміни розміру внутрішнього масиву при додаванні елементів.

Усі абстракції повинні вирішити одну і ту ж проблему, створити масив без порожніх слотів, який містить усі значення, і повернути їх.

Якщо вам потрібна гнучкість, ви можете створити достатньо великий список, який ви можете використовувати для передачі, то зробіть це. інше використовувати масив і поділитися цим об'єктом, безпечним для потоків. Також новий Span допомагає обмінюватися даними, не копіюючи списки навколо.

Щоб відповісти на запитання:

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

4

Тож якщо у вас є існуючий масив, моє швидке виправлення буде

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

Тепер просто замініть початковий масив на новий

originalArray = tempList.ToArray();

Вирішив моє рішення
прагуан

3

Append<TSource>До IEnumerable<TSource>.NET Framework 4.7.1 та .NET Core 1.0 додано новий метод .

Ось як його використовувати:

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

Зауважте, що якщо ви хочете додати елемент на початку масиву, ви можете скористатися новим Prepend<TSource>методом.



2

Що з використанням методу розширення? Наприклад:

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

наприклад:

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

Зауважте, це імітує таку поведінку розширення Uniq Uniq (використовується для об'єднання двох масивів у новий) та вимагає функціонування бібліотеки Linq.


1

Я згоден з Едом. C # не робить це просто так, як це робить VB із ReDim Preserve. Без колекції вам доведеться скопіювати масив у більший.


2
Дякую, Боже! ReDim неймовірно повільний при зловживанні. =)
Ед С.

ReDim Preserveпросто копіює масив у лагерний. Чудотворного масиву не змінюється.
Олів'є Якот-Дескомб

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

На жаль, використання списку не працюватиме у всіх ситуаціях. Список і масив насправді різні і не є на 100% взаємозамінними. Це залежало б від обставин, якщо це буде прийнятною проблемою.


0

Оскільки це питання не задоволено наданою відповіддю, я хотів би додати цю відповідь :)

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;  
    } 
  }
 }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.