Добавить новый элемент в существующий массив в c # .net


134

Как добавить новый элемент в существующий массив строк в C # .net?

Мне нужно сохранить существующие данные.

Ответы:


121

Я бы использовал список, если вам нужен массив с динамическим размером:

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

27
И, если требуется, выполните ls.ToArray () в конце
— Нараяна

2
Использование другой механики, чем задано в вопросе, не является ответом.
— user11909

@ user2190035: Не знаю, откуда у вас эта идея, но 111 человек, проголосовавших за, не согласятся с вами. Если вы знаете, как лучше расширить массив, обязательно опубликуйте его. Я сомневаюсь, что ваше перераспределение и ручное копирование будет лучше, чем использование списка. Иногда ответ - «не делай этого».
— Эд С.

@ EdS. Вопрос заключался в том, как добавить элемент в существующий массив строк , но в этом ответе вообще нет массива, вместо этого создается новый List <>. В моем приложении я не могу изменить тип на List <>, поэтому мне нужно изменить размер массива (сделать копию ...). Мне помог ответ Али Эрсёза.
— user11909

1
Зачем тебе это? Если бы вам пришлось, я бы предложил Concat ()
— Эд С.

100

Это могло быть решением;

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

Но для массива с динамическим размером я бы тоже предпочел список.


@Konrad, это обязательно сохранит данные в массиве.
— Али Эрсез

1
это не подходит для вызова дольше, чем несколько раз. потому что функция «Изменить размер» имеет огромную производительность. баг на один-два раза, это очень хорошо.
— объявление

53

Использование LINQ:

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

Мне нравится использовать это, так как это однострочный текст, и его очень удобно встраивать в оператор switch, простой оператор 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 для первого параметра.

Есть списки, которые могут динамически выделять новые слоты для новых элементов. Это, например, List <T> . Они содержат неизменяемые массивы и при необходимости меняют их размер (List <T> не является реализацией связанного списка!). ArrayList - это то же самое без Generics (с массивом Object ).

LinkedList <T> - это реальная реализация связанного списка. К сожалению, вы можете добавить в список только элементы LinkListNode <T>, поэтому вы должны заключить свои собственные элементы списка в этот тип узла. Я думаю, что его используют нечасто.


Я думаю, вы имели в виду Array.Copy
— user123456

2
Единственный ответ, который дает некоторую информацию о том, почему это невозможно, и не просто предлагает использовать список ...
— Гилад Грин

Я считаю, что 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();

Спасибо, это было очень полезно, я добавил возможность удалить элемент (надеюсь, что вас это устраивает).
— Tal Segal

@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

Использование списка было бы лучшим вариантом для управления памятью.


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

Обратите внимание, что это имитирует поведение расширения Linq Uniion (используется для объединения двух массивов в новый) и требует для работы библиотеки Linq.


1

Я согласен с Эдом. C # не упрощает эту задачу, как VB с ReDim Preserve. Без коллекции вам придется скопировать массив в более крупный.


2
Слава Богу! ReDim работает очень медленно при злоупотреблении. =)
— Эд С.

ReDim Preserveпросто копирует массив в лагерный. Чудесного изменения размера массива нет.
— Оливье Жако-Декомб


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.