web-dev-qa-db-ja.com

値の行を2D配列から1D配列にコピーするにはどうすればよいですか?

次のオブジェクトがあります

int [,] oGridCells;

これは、固定の最初のインデックスでのみ使用されます

int iIndex = 5;
for (int iLoop = 0; iLoop < iUpperBound; iLoop++)
{
  //Get the value from the 2D array
  iValue = oGridCells[iIndex, iLoop];

  //Do something with iValue
}

.NETに、固定の最初のインデックスの値を(値をループする以外に)単一の次元配列に変換する方法はありますか?

配列が1回だけループされている場合、コードが高速化されるとは思えません(また、速度が低下する可能性もあります)。ただし、配列が頻繁に操作されている場合は、多次元配列よりも単一次元配列の方が効率的です。

質問をする主な理由は、本番コードに使用するのではなく、実行できるかどうか、どのように実行できるかを確認することです。

17
stevehipwell

次のコードは、16バイト(4 int)を2次元配列から1次元配列にコピーする方法を示しています。

int[,] oGridCells = {{1, 2}, {3, 4}};
int[] oResult = new int[4];
System.Buffer.BlockCopy(oGridCells, 0, oResult, 0, 16);

正しいバイトオフセットを指定することにより、配列から1行だけを選択的にコピーすることもできます。この例では、3行の2次元配列の中央の行をコピーします。

int[,] oGridCells = {{1, 2}, {3, 4}, {5, 6}};
int[] oResult = new int[2];
System.Buffer.BlockCopy(oGridCells, 8, oResult, 0, 8);
32
BlueMonkMN

編集:

方法があることに気づきました!確かに、それはおそらくそれだけの価値はありません。 安全でないコード を使用します。完全な例、両方の方法を示していますが、以下は安全ではありません。

public class MultiSingleUnsafe
{
    public static unsafe void Main(String[] a)
    {
    int rowCount = 6;
    int iUpperBound = 10;
    int [,] oGridCells = new int[rowCount, iUpperBound];

    int iIndex = rowCount - 2; // Pick a row.

    for(int i = 0; i < iUpperBound; i++)
    {
        oGridCells[iIndex, i] = i;
    }

    for (int iLoop = 0; iLoop < iUpperBound; iLoop++)
    {
        //Get the value from the 2D array
        int iValue = oGridCells[iIndex, iLoop];
        Console.WriteLine("Multi-dim array access iValue: " + iValue);
        //Do something with iValue
    }

    fixed(int *lastRow = &(oGridCells[iIndex,0]))
    {   
        for (int iLoop = 0; iLoop < iUpperBound; iLoop++)
        {
        int iValue = lastRow[iLoop];
        Console.WriteLine("Pointer access iValue: " + iValue);
        }
    }
    }
}

C#で多次元配列を一次元配列にキャストする方法はありません。もちろん、新しい1次元配列を作成してそこにコピーすることもできます。ただし、値を複数回ループしても、パフォーマンスが向上するとは思いません。ダレンが言ったように、内部的にはとにかくそれはすべてポインタ演算です。確実にしたい場合は、プロファイルを作成します。

2

あなたはこれを試すことができます:

 int[,] twoD = new int[2,2];
 twoD[0, 0] = 1;
 twoD[0, 1] = 2;
 twoD[1, 0] = 3;
 twoD[1, 1] = 4;

 int[] result = twoD.Cast<int>().Select(c => c).ToArray();

結果は、データを含む整数配列になります。

1, 2, 3, 4
1
Willy David Jr

各配列への参照を取得することはできません。ただし、 ギザギザの配列 を使用することはできます。

1
Groo

「しかし、配列が頻繁に操作されている場合は、多次元配列よりも単一次元配列の方が効率的です。」

去年の夏に正確にプロファイリングを行いましたが、2Dアレイと1Dアレイのパフォーマンスに大きな違いがないことに驚きました。

ギザギザの配列のパフォーマンスはテストしていません。

1
AnnaR

可能であれば驚かれることでしょう。oGridCells[iIndex, iLoop]oGridCells[iIndex * iLoop]の一種の省略形(内部的にはMSIL)であり、多次元配列はこのための構文糖衣です。

質問に答えるには:いいえ。値をループする必要があります。

0
Daren Thomas