webdevqa.jp.net

C#で配列を追加する最も効率的な方法は?

古い学校のActiveXからdoubleの配列の形式でデータを引き出しています。最初に、実際に取得するサンプルの最終数がわかりません。

これらの配列をC#で連結してシステムから引き出す最も効率的な方法は何ですか?

63
Huck

実際の配列に追加することはできません-配列のサイズは作成時に固定されます。代わりに、List<T>必要に応じて成長できます。

または、配列のリストを保持し、すべてを取得した場合にのみすべてを連結します。

Eric Lippertの配列に関するブログ投稿 を参照してください。私が現実的に提供できる以上の詳細と洞察については:)

77
Jon Skeet

同じ型の2つの配列を組み合わせて3番目の配列にしたい場合、非常に簡単な方法があります。

コードは次のとおりです。

String[] theHTMLFiles = Directory.GetFiles(basePath, "*.html");
String[] thexmlFiles = Directory.GetFiles(basePath, "*.xml");
List<String> finalList = new List<String>(theHTMLFiles.Concat<string>(thexmlFiles));
String[] finalArray = finalList.ToArray();
28
Michael Bahig

ここにある答えをお勧めします: C#で2つの配列を連結するにはどうすればよいですか?

例えば.

var z = new int[x.Length + y.Length];
x.CopyTo(z, 0);
y.CopyTo(z, x.Length);
25
GeorgePotter

.Net 4に標準装備されているlinq拡張機能を使用すると、配列の連結が簡単になります。

覚えておくべき最大のことは、linqが_IEnumerable<T>_オブジェクトで動作するため、結果として配列を取得するには、最後に.ToArray()メソッドを使用する必要があります

2つのバイト配列を連結する例:

_byte[] firstArray = {2,45,79,33};
byte[] secondArray = {55,4,7,81};
byte[] result = firstArray.Concat(secondArray).ToArray();
_
22
Lenny Woods

このソリューションはとても楽しいように見えますが、2つのステートメントで配列を連結することは可能です。大きなバイト配列を処理している場合、リンクリストを使用して各バイトを含めるのは非効率的だと思います。

ストリームからバイトを読み取り、その場でバイト配列を拡張するためのコードサンプルを次に示します。

 byte [] buf = new byte [8192]; 
 byte [] result = new byte [0]; 
 int count = 0; 
 do 
 {
 count = resStream.Read(buf、0、buf.Length); 
 if(count!= 0)
 {
 Array.Resize (ref result、result.Length + count); 
 Array.Copy(buf、0、result、result.Length-count、count); 
} 
} 
 while(count> 0); //さらに読み込むデータはありますか?
 resStream.Close(); 
7
Hugo

これを使用して、ループなしで2つの配列を追加できます。

配列の1つに結合する同じタイプの2つの配列がある場合、非常に簡単な方法があります。

コードは次のとおりです。

String[] TextFils = Directory.GetFiles(basePath, "*.txt");
String[] ExcelFils = Directory.GetFiles(basePath, "*.xls");
String[] finalArray = TextFils.Concat(ExcelFils).ToArray();

または

String[] Fils = Directory.GetFiles(basePath, "*.txt");
String[] ExcelFils = Directory.GetFiles(basePath, "*.xls");
Fils = Fils.Concat(ExcelFils).ToArray();
6
SGRao

最後にあるアイテムの数を概算できる場合は、countをパラメーターとして受け取るListコンストラクターのオーバーロードを使用します。高価なリストの複製をいくつか保存します。そうでなければ、あなたはそれを支払う必要があります。

4
Olmo

最終結果を連続した配列に連結する必要がない場合があります。代わりに、Jonの提案に従ってリストに追加し続けます。最終的には jagged array になります(実際、ほぼ長方形です)。インデックスで要素にアクセスする必要がある場合は、次のインデックススキームを使用します。

double x = list[i / sampleSize][i % sampleSize];

ギザギザの配列の反復も簡単です。

for (int iRow = 0; iRow < list.Length; ++iRow) {
  double[] row = list[iRow];
  for (int iCol = 0; iCol < row.Length; ++iCol) {
    double x = row[iCol];
  }
}

これにより、メモリアクセスとコピーが節約されますが、要素へのアクセスが若干遅くなります。これが最終的なパフォーマンス向上になるかどうかは、データのサイズ、データアクセスパターン、およびメモリの制約によって異なります。

4
Constantin

以下は、コンスタンタンが言ったことに基づいた使用可能なクラスです。

class Program
{
    static void Main(string[] args)
    {
        FastConcat<int> i = new FastConcat<int>();
        i.Add(new int[] { 0, 1, 2, 3, 4 });
        Console.WriteLine(i[0]);
        i.Add(new int[] { 5, 6, 7, 8, 9 });
        Console.WriteLine(i[4]);

        Console.WriteLine("Enumerator:");
        foreach (int val in i)
            Console.WriteLine(val);

        Console.ReadLine();
    }
}

class FastConcat<T> : IEnumerable<T>
{
    LinkedList<T[]> _items = new LinkedList<T[]>();
    int _count;

    public int Count
    {
        get
        {
            return _count;
        }
    }

    public void Add(T[] items)
    {
        if (items == null)
            return;
        if (items.Length == 0)
            return;

        _items.AddLast(items);
        _count += items.Length;
    }

    private T[] GetItemIndex(int realIndex, out int offset)
    {
        offset = 0; // Offset that needs to be applied to realIndex.
        int currentStart = 0; // Current index start.

        foreach (T[] items in _items)
        {
            currentStart += items.Length;
            if (currentStart > realIndex)
                return items;
            offset = currentStart;
        }
        return null;
    }

    public T this[int index]
    {
        get
        {
            int offset;
            T[] i = GetItemIndex(index, out offset);
            return i[index - offset];
        }
        set
        {
            int offset;
            T[] i = GetItemIndex(index, out offset);
            i[index - offset] = value;
        }
    }

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
        foreach (T[] items in _items)
            foreach (T item in items)
                yield return item;
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion
}

Olmoの提案は非常に優れていますが、これを追加します。サイズがわからない場合は、少し小さくするよりも少し大きくする方が良いでしょう。リストがいっぱいになると、リストのサイズが2倍になり、要素が追加されることに注意してください。

たとえば、約50個の要素が必要だとします。 50個の要素サイズを使用し、要素の最終数が51である場合、49個の無駄な位置を持つ100個のサイズのリストで終わります。

0
rgargente