2次元配列を扱うコードを書いてたら、行や列に対してLINQが使えないのが微妙にストレスだったんで、簡単な拡張メソッドを書いてみました。
/// <summary>
/// 2次元方向
/// </summary>
public enum SquareDirection { Row = 0, Column = 1 }
/// <summary>
/// 配列の拡張メソッド
/// </summary>
public static class ArrayEx
{
/// <summary>
/// 2次元配列向け列クラス
/// </summary>
/// <typeparam name="T"></typeparam>
public class SquareArrayColumn<T> : IEnumerable<T>
{
/// <summary>
/// 2次元配列
/// </summary>
private T[,] _array;
/// <summary>
/// 列インデックス
/// </summary>
private int _colIndex;
/// <summary>
/// インデクサ
/// </summary>
/// <param name="rowIndex">行インデックス</param>
/// <returns>要素</returns>
public T this[int rowIndex]
{
get => _array[rowIndex, _colIndex];
set => _array[rowIndex, _colIndex] = value;
}
/// <summary>
/// Length
/// </summary>
public int Length => _array.GetLength(0);
/// <summary>
/// Constructor
/// </summary>
/// <param name="array">2次元配列</param>
/// <param name="rowIndex">行インデックス</param>
public SquareArrayColumn(T[,] array, int colIndex)
{
_array = array;
_colIndex = colIndex;
}
/// <summary>
/// GetEnumerator()の実装
/// </summary>
/// <returns>IEnumerator<T></returns>
public IEnumerator<T> GetEnumerator()
{
for (var i = 0; i < Length; i++)
yield return this[i];
}
/// <summary>
/// GetEnumerator()の実装
/// </summary>
/// <returns>IEnumerator</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
/// <summary>
/// 2次元配列向け行クラス
/// </summary>
/// <typeparam name="T">型パラメータ</typeparam>
public class SquareArrayRow<T> : IEnumerable<T>
{
/// <summary>
/// 2次元配列
/// </summary>
private T[,] _array;
/// <summary>
/// 行インデックス
/// </summary>
private int _rowIndex;
/// <summary>
/// インデクサ
/// </summary>
/// <param name="colIndex">列インデックス</param>
/// <returns>要素</returns>
public T this[int colIndex]
{
get => _array[_rowIndex, colIndex];
set => _array[_rowIndex, colIndex] = value;
}
/// <summary>
/// Length
/// </summary>
public int Length => _array.GetLength(1);
/// <summary>
/// Constructor
/// </summary>
/// <param name="array">2次元配列</param>
/// <param name="rowIndex">行インデックス</param>
public SquareArrayRow(T[,] array, int rowIndex)
{
_array = array;
_rowIndex = rowIndex;
}
/// <summary>
/// GetEnumerator()の実装
/// </summary>
/// <returns>IEnumerator<T></returns>
public IEnumerator<T> GetEnumerator()
{
for (var i = 0; i < Length; i++)
yield return this[i];
}
/// <summary>
/// GetEnumerator()の実装
/// </summary>
/// <returns>IEnumerator</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
/// <summary>
/// 2次元配列から行を取得する
/// </summary>
/// <typeparam name="T">型パラメータ</typeparam>
/// <param name="array">this 2次元配列</param>
/// <param name="rowIndex">行インデックス</param>
/// <returns>行オブジェクト</returns>
public static SquareArrayRow<T> Rows<T>(this T[,] array, int rowIndex)
{
if (rowIndex < 0 || array.GetLength(0) <= rowIndex)
throw new IndexOutOfRangeException();
return new SquareArrayRow<T>(array, rowIndex);
}
/// <summary>
/// 2次元配列から行を列挙する
/// </summary>
/// <typeparam name="T">型パラメータ</typeparam>
/// <param name="array">this 2次元配列</param>
/// <returns>行オブジェクトの列挙子</returns>
public static IEnumerable<SquareArrayRow<T>> Rows<T>(this T[,] array)
{
for (var row = 0; row < array.GetLength(0); row++)
yield return array.Rows(row);
}
/// <summary>
/// 2次元配列から列を取得する
/// </summary>
/// <typeparam name="T">型パラメータ</typeparam>
/// <param name="array">this 2次元配列</param>
/// <param name="colIndex">列インデックス</param>
/// <returns>行オブジェクト</returns>
public static SquareArrayColumn<T> Cols<T>(this T[,] array, int colIndex)
{
if (colIndex < 0 || array.GetLength(1) <= colIndex)
throw new IndexOutOfRangeException();
return new SquareArrayColumn<T>(array, colIndex);
}
/// <summary>
/// 2次元配列から列を列挙する
/// </summary>
/// <typeparam name="T">型パラメータ</typeparam>
/// <param name="array">this 2次元配列</param>
/// <returns>行オブジェクトの列挙子</returns>
public static IEnumerable<SquareArrayColumn<T>> Cols<T>(this T[,] array)
{
for (var col = 0; col < array.GetLength(1); col++)
yield return array.Cols(col);
}
/// <summary>
/// 2次元配列をまとめて列挙する
/// </summary>
/// <typeparam name="T">型パラメータ</typeparam>
/// <param name="array">2次元配列</param>
/// <param name="direction">方向</param>
/// <returns>列挙子</returns>
public static IEnumerable<T> Flatten<T>(this T[,] array, SquareDirection direction = SquareDirection.Row)
{
IEnumerable<T> rowDirection()
{
for (var row = 0; row < array.GetLength(0); row++)
{
for (var col = 0; col < array.GetLength(1); col++)
{
yield return array[row, col];
}
}
}
IEnumerable<T> colDirection()
{
for (var col = 0; col < array.GetLength(1); col++)
{
for (var row = 0; row < array.GetLength(0); row++)
{
yield return array[row, col];
}
}
}
if (direction == SquareDirection.Row)
return rowDirection();
else
return colDirection();
}
}
使い方は、拡張メソッドなので任意の2次元配列 (array<T>[行,列]
) に対して、
array.Rows()
で行単位での Enumerator、
array.Cols()
で列単位の Enumerator を返します。
例えば、2次元配列の行単位の合計を取得するには
var array = new int[,]
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
// 行毎の合計を撮る
var sums = array.Rows.Select(r => r.Sum()).ToArray(); // => [ 6, 15, 24 ]
という感じ。