c#.netの既存の配列に新しい項目を追加する


134

C#.netの既存の文字列配列に新しい項目を追加する方法

既存のデータを保持する必要があります。

回答:


121

動的なサイズの配列が必要な場合は、リストを使用します。

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

27
そして必要に応じて、最後にls.ToArray()を実行します
Narayana

2
質問で尋ねられた以外のメカニズムを使用することは、答えではありません。
user11909

@ user2190035:どこでそのアイデアを得たのかわからず、賛成票を投じた111人が反対します。配列を拡張するより良い方法を知っているなら、ぜひ、投稿してください。リストの使用よりも、再割り当てと手動コピーの方が良いとは思えません。時々答えは「それをしないでください」です。
Ed S.

@EdS。質問は、既存の文字列配列に項目を追加する方法でしたが、この回答には配列がまったくなく、代わりに新しいリスト<> が作成されます。私のアプリケーションでは、タイプをList <>に変更できないため、配列のサイズを変更する必要があります(コピーを作成しています...)。AliErsözの回答が役に立ちました。
user11909

@ user2190035:IEnumerable <T> .ToArray()。私は毎日C#を作成しており、そのような配列のサイズを変更する必要はありませんでした。
Ed S.

100

それが解決策になるかもしれません。

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

ただし、動的サイズの配列の場合は、リストも使用します。


@Konrad、それは確かに配列内のデータを保存します。
AliErsöz、2008年

1
これは、数回以上の起動には適していません。「サイズ変更」機能は非常に優れているためです。バグが1〜2回発生すると、これは非常に良いことです。
2014

53

LINQの使用:

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

これはワンライナーであり、switchステートメント、単純なifステートメントに埋め込む、または引数として渡すのに非常に便利なので、私はこれを使用するのが好きです。

編集:

new[] { newitem }小さい1項目の一時的な配列を作成するため、気に入らない人もいます。これは、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#の1行のコードで配列に追加する方法」を検索しているときに非常に便利です。次回は、このコメントでそれを再度見つけることができれば幸いです。
ゲイリー、2014年

28

非常に古い質問ですが、これを追加したかったのです。

ワンライナーを探している場合は、以下のコードを使用できます。これは、列挙型と「新しい」(質問が出されたため)初期化構文を受け入れるリストコンストラクターを組み合わせます。

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を意味していると思います
user123456 '16

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

ありがとうございました。これは非常に役に立ちました。アイテムを削除するオプションを追加しました(これで問題ないことを願っています)。
Tal Segal

@TalSegalどういたしまして。必要に応じてコードを使用してください!
dblood 2013年

6

Arrayを不変で固定サイズに保つことをお勧めします。

あなたがシミュレートすることができますAddExtension MethodIEnumerable.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のリストは、アイテムが追加されたときに内部配列のサイズが変更されないように、いくつかの余分なスペースを持つバッファースペースを持つ配列です。

すべての抽象化は同じ問題を解決し、すべての値を保持してそれらを返す空のスロットのない配列を作成する必要があります。

柔軟性が必要な場合は、渡すために使用できる十分に大きなリストを作成できます。それ以外の場合は、配列を使用してそのスレッドセーフオブジェクトを共有します。また、新しいスパンにより、リストをコピーすることなくデータを共有できます。

質問に答えるには:

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

これは、LinqのUniion拡張機能(2つの配列を新しい配列に結合するために使用)のこの動作を模倣しており、Linqライブラリーが機能する必要があることに注意してください。


1

私はエドに同意します。C#は、VBがReDim Preserveで行うようにこれを容易にしません。コレクションがない場合は、配列をより大きな配列にコピーする必要があります。


2
ああ、助かった!乱用すると、ReDimは非常に遅くなります。=)
Ed S.

ReDim Preserve単に配列を大きい配列にコピーします。奇跡的な配列のサイズ変更はありません。
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

残念ながら、リストの使用はすべての状況で機能するわけではありません。リストと配列は実際には異なり、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;  
    } 
  }
 }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.