在c#.net中的现有数组中添加新项目


134

如何在C#.net的现有字符串数组中添加新项目?

我需要保留现有数据。

Answers:


121

如果需要动态大小的数组,我将使用List:

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

27
如果需要,请在末尾执行ls.ToArray()
Narayana

2
使用不是问题所要求的其他机械手不是答案。
user11909 '19

@ user2190035:不确定您从何处得到这个想法,投票支持的111个人将不同意您的意见。如果您知道扩展数组的更好方法,请发布。我怀疑您的重新分配和手动复制会比使用列表更好。有时答案是“不要那样做”。
Ed S.

@EdS。问题是,如何将项目添加到现有的字符串数组中,但是这个答案根本没有数组,而是创建了一个新的 List <>。在我的应用程序中,我无法将类型更改为List <>,因此必须调整数组的大小(制作副本...)。AliErsöz的回答对我有所帮助。
user11909 '19

@ user2190035:IEnumerable <T> .ToArray()。我每天都在编写C#,而我从未如此调整数组的大小。
Ed S.19年

100

那可能是一个解决方案;

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

但是对于动态大小的数组,我也希望列出。


@Konrad,这肯定会保留数组中的数据。
阿里·埃索兹(AliErsöz)

1
这不适合多次调用。因为“调整大小”功能具有出色的性能。错误一两次,这非常好。
2014年

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 2012年

在搜索“如何在c#中的一行代码中将数组追加到数组中”时,发现它非常有用-希望此注释足以下次再次找到它。
gary 2014年

28

很老的问题,但仍想添加。

如果您正在寻找单线飞机,则可以使用以下代码。它结合了接受可枚举的列表构造函数和“ new”(引发问题)初始化程序语法。

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

26

在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是同一件事。

LinkedList <T>是一个实际的链表实现。不幸的是,您只能将LinkListNode <T>元素添加到列表中,因此必须将自己的列表元素包装到此节点类型中。我认为它的使用并不常见。


我认为您的意思是Array.Copy
2015年

2
唯一的答案提供了一些信息,说明为什么不可能这样做,而不仅仅是建议使用列表...
Gilad Green,

我相信Aray.Resize可以调整数组的大小而不会丢失其内容。docs.microsoft.com/en-us/dotnet/api/...
阿卜杜拉齐兹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的逻辑来使用泛型类型创建扩展方法,从而扩展@Stephen Chung提供的答案。

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

最好保持Array不可变且固定大小。

您可以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();

解决了我的问题
praguan

3

自.NET Framework 4.7.1和.NET Core 1.0以来,Append<TSource>已添加了一种新方法IEnumerable<TSource>

使用方法如下:

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

请注意,如果要在数组的开头添加元素,则可以改用new 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);

请注意,这模仿了Linq的Uniion扩展(用于将两个数组合并为一个新数组)的行为,并且需要Linq库起作用。


1

我同意埃德。C#并不像VB使用ReDim Preserve那样简单。如果没有集合,则必须将阵列复制到更大的阵列中。


2
感谢上帝!滥用时,ReDim的速度非常慢。=)
艾德·S。2010年

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;  
    } 
  }
 }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.