2次元配列をLinqする in C#
2 次元配列の各要素をそれぞれの次元のインデックスとともに別の形に変換し、元と同じサイズの 2 次元配列に戻したい、、、そこで拡張メソッドを作りました。
まずは、2 次元配列の各要素をそれぞれの次元のインデックスとともに新しい形に射影するメソッドSelect2D。
public static IEnumerable<TResult> Select2D<TArray, TResult>( this TArray[,] array2Dsource, Func<TArray, int, int, TResult> selector) { for (int i = 0; i < array2Dsource.GetLength(0); ++i) { for (int j = 0; j < array2Dsource.GetLength(1); ++j) { TArray elem = array2Dsource[i, j]; TResult result = selector(elem, i, j); yield return result; } } }
こんな感じで使います。
int[,] array2Dsource = new int[,] { { 0, 1, 2 }, { 3, 4, 5 }, }; IEnumerable<string> actual = array2Dsource.Select2D( (n, i, j) => String.Format("n={0}, i={1}, j={2}", n, i, j));
次は、IEnumerable<T>を指定サイズの 2 次元配列に変換するToArray2D。
public static TResult[,] ToArray2D<TResult>( this IEnumerable<TResult> source, int numRows, int numColumns) { if (numRows < 0) { string message = String.Format("numRows ({0}) must be >= 0.", numRows); throw new ArgumentException(message); } if (numColumns < 0) { string message = String.Format("numColumns ({0}) must be >= 0.", numColumns); throw new ArgumentException(message); } int arrayLength = numRows * numColumns; int sourceCount = source.Count(); if (arrayLength != sourceCount) { string message = String.Format( "Number of source items ({0}) is not equal to numRows ({1}) x numColumns ({2}).", sourceCount, numRows, numColumns); throw new ArgumentException(message); } TResult[,] result = new TResult[numRows, numColumns]; int rowIndex = 0; int columnIndex = 0; foreach (TResult item in source) { result[rowIndex, columnIndex] = item; ++columnIndex; if (numColumns <= columnIndex) { columnIndex = 0; ++rowIndex; } } return result; }
最後に、IEnumerable<T>を指定の 2 次元配列と同じサイズの 2 次元配列にするToArray2DLike。
public static TResult[,] ToArray2DLike<TArray, TResult>( this IEnumerable<TResult> source, TArray[,] array2Dref) { int numRows = array2Dref.GetLength(0); int numColumns = array2Dref.GetLength(1); TResult[,] result = source.ToArray2D(numRows, numColumns); return result; }