web-dev-qa-db-ja.com

2D配列から1D列配列と1D行配列を取得するにはどうすればよいですか? (C#.NET)

私は_double[,] Array;_を持っています。すべての要素のコピーを作成せずに(forを使用して)double[] ColumnArray0 = Array[0,].toArray()double[] RowArray1 = Array[,1].toArray()のようなものを取得することは可能ですか?

ありがとう。

11
Jose Kiwi

配列は、すべてのエントリが連続して格納されるメモリ領域です。メモリ内のデータレイアウトに応じて、これは行または列のいずれかでのみ可能です。

2D配列double[,]タイプの代わりに、配列double[][]の配列を使用することをお勧めします。

double[][] Array2d = new double[10][];
Array2d[0] = new double[10];
Array2d[1] = new double[10];
...

and then:
double[] RowArray0 = Array2d[0];

配列へのデータの配置方法によっては、Array2dを列配列として扱うこともできます。しかし、両方を同時に持つことは不可能です。

こちらもご覧ください: 多次元配列[] [] vs [、]

5
thalm

非常に遅れていますが、私は質問に対する別の答えを提供したいと思います。

質問の最初の重要な部分は、マトリックスの完全な行OR列にアクセスできるようにすることでした。これを行う1つの可能性は、拡張メソッドを使用することです。

public static class MatrixExtensions
{
  /// <summary>
  /// Returns the row with number 'row' of this matrix as a 1D-Array.
  /// </summary>
  public static T[] GetRow<T>(this T[,] matrix, int row)
  {
    var rowLength = matrix.GetLength(1);
    var rowVector = new T[rowLength];

    for (var i = 0; i < rowLength; i++)
      rowVector[i] = matrix[row, i];

    return rowVector;
  }



  /// <summary>
  /// Sets the row with number 'row' of this 2D-matrix to the parameter 'rowVector'.
  /// </summary>
  public static void SetRow<T>(this T[,] matrix, int row, T[] rowVector)
  {
    var rowLength = matrix.GetLength(1);

    for (var i = 0; i < rowLength; i++)
      matrix[row, i] = rowVector[i];
  }



  /// <summary>
  /// Returns the column with number 'col' of this matrix as a 1D-Array.
  /// </summary>
  public static T[] GetCol<T>(this T[,] matrix, int col)
  {
    var colLength = matrix.GetLength(0);
    var colVector = new T[colLength];

    for (var i = 0; i < colLength; i++)
      colVector[i] = matrix[i, col];

    return colVector;
  }



  /// <summary>
  /// Sets the column with number 'col' of this 2D-matrix to the parameter 'colVector'.
  /// </summary>
  public static void SetCol<T>(this T[,] matrix, int col, T[] colVector)
  {
    var colLength = matrix.GetLength(0);

    for (var i = 0; i < colLength; i++)
      matrix[i, col] = colVector[i];
  }
}

使用例:

double[,] myMatrix = ... // Initialize with desired size and values.
double[] myRowVector = myMatrix.GetRow(2); // Gets the third row.
double[] myColVector = myMatrix.GetCol(1); // Gets the second column.
myMatrix.SetCol(2, myColVector); // Sets the third column to the second column.

最初に注意することは、これらのジェネリックメソッドを任意の種類の[、]-行列および対応する[]-ベクトルで使用できることです。 Tsをdoublesに置き換えると、「double」の特定のバージョンが得られると想像してください(OPからの質問に応じて)。

2つ目は、行の取得と設定ではArray.Copyを使用し、列の取得と設定ではループを使用することです。これは、C#の Row-Major order が原因で、最初の処理は許可されますが、2番目の処理は許可されません。もちろん、コメントアウトされているように、両方ともループで実装できます。

Set-Methodsに正しいディメンションを渡すようにしてください。そうしないと、プログラムがクラッシュします(エラーとディメンションのチェックを簡単に追加できます)。ロジック全体は、double[][]のようなギザギザの配列にも実装できますが、OPは特に多次元配列を要求しました。

質問の2番目の部分については、行列がdoubleで構成されていて、doubleが値型であるため、値は常にコピーされます。したがって、値をコピーしないという望ましい動作は不可能です。ただし、オブジェクトをTとして使用する場合は、オブジェクトを指す参照のみがコピーされ、オブジェクト自体はコピーされません(したがって、「コピーされた」オブジェクトの変更に注意してください)。

最後に、本当にdouble値をコピーしたくない場合は、行列全体を渡して(参照のみが渡される)、目的の列や行を直接ループすることをお勧めします。

11
Timitry