C#で長方形配列から1次元配列を抽出する最良の方法は何ですか?
質問
ギザギザの配列ではなく、長方形の文字列配列があるとします
string[,] strings = new string[8, 3];
これから一次元配列を抽出する最良の方法は何ですか(単一の行または単一の列)?もちろん、forループでこれを行うことができますが、.NETにはよりエレガントな方法が組み込まれていることを望んでいます。
抽出された文字列配列をオブジェクト配列に変換するためのボーナスポイント。
解決
長方形配列の場合:
string[,] rectArray = new string[3,3] {
{"a", "b", "c"},
{"d", "e", "f"},
{"g", "h", "i"} };
var rectResult = rectArray.Cast<object>().ToArray();
そしてギザギザの配列の場合:
string[][] jaggedArray = {
new string[] {"a", "b", "c", "d"},
new string[] {"e", "f"},
new string[] {"g", "h", "i"} };
var jaggedResult = jaggedArray.SelectMany(s => s).Cast<object>().ToArray();
他のヒント
文字列配列を簡単にオブジェクト配列にキャストできます-他の方法では機能しません。ただし、実際に抽出するには、 Array.Copy
では、ソースとターゲットのランクが同じである必要があり、 Buffer.BlockCopy
は、値型の配列でのみ機能します。しかし奇妙に思えます...
LINQを使用して、1つのステートメントで行または列を追加できますが、非効率的です(内部的にリストを作成してから、配列に変換する必要があるため、自分で実行する場合は、配列を適切なサイズに事前に割り当てて、直接コピーします。)
行のコピー( rowNum
はコピーする行です):
object[] row = Enumerable.Range(0, rowLength)
.Select(colNum => (object) stringArray[rowNum, colNum])
.ToArray();
列のコピー( colNum
はコピーする列です):
object[] column = Enumerable.Range(0, columnLength)
.Select(rowNum => (object) stringArray[rowNum, colNum])
.ToArray();
これがforeachループよりも本当に優れているか簡単であるかはわかりません-特に ExtractRow
メソッドと ExtractColumn
メソッドを記述して再利用する場合。
明確にしたいだけです(例と、何が求められているのか)。
ジャグ配列は配列の配列であり、次のように宣言されます。
string[][] data = new string[3][];
data[0] = new string[] { "0,[0]", "0,[1]", "0,[2]" };
data[1] = new string[] { "1,[0]", "1,[1]", "1,[2]" ];
data[2] = new string[] { "2,[0]", "1,[1]", "1,[2]" };
長方形配列と、複数の次元を保持する単一の配列として定義されている場合:
string[,] data = new string[3,3];
data[0,0] = "0,0";
data[0,1] = "0,1";
data[0,2] = "0,2";
...etc
このため、 ギザギザの配列 はIQueryable / IEnumerableです。反復ごとに配列を受け取ることができるためです。 長方形配列 はではありません IQueryable / IEnumerableですが、要素はフルディメンション(0,0 0,1..etc)でアドレス指定されるため、その場合、LinqまたはArray用に作成された事前定義関数を使用することはできません。
次のように、配列を1回反復する(および必要なことを達成する)ことができます:
/// INPUT: rowIndex, OUTPUT: An object[] of data for that row
int colLength = stringArray.GetLength(1);
object[] rowData = new object[colLength];
for (int col = 0; col < colLength; col++) {
rowData[col] = stringArray[rowIndex, col] as object;
}
return rowData;
/// INPUT: colIndex, OUTPUT: An object[] of data for that column
int rowLength = stringArray.GetLength(0);
object[] colData = new object[rowLength];
for (int row = 0; r < rowLength; row++) {
colData[row] = stringArray[row, colIndex] as object;
}
return colData;
これが役立つことを願って:)
LINQが答えです
static object[] GetColumn(string[][] source, int col) {
return source.Iterate().Select(x => source[x.Index][col]).Cast<object>().ToArray();
}
static object[] GetRow(string[][] source, int row) {
return source.Skip(row).First().Cast<object>().ToArray();
}
public class Pair<T> {
public int Index;
public T Value;
public Pair(int i, T v) {
Index = i;
Value = v;
}
}
static IEnumerable<Pair<T>> Iterate<T>(this IEnumerable<T> source) {
int index = 0;
foreach (var cur in source) {
yield return new Pair<T>(index, cur);
index++;
}
}
Array.Copyを使用して行を簡単にコピーできます:
int[][] arDouble = new int[2][];
arDouble[0] = new int[2];
arDouble[1] = new int[2];
arDouble[0][0] = 1;
arDouble[0][1] = 2;
arDouble[1][0] = 3;
arDouble[1][1] = 4;
int[] arSingle = new int[arDouble[0].Length];
Array.Copy(arDouble[0], arSingle, arDouble[0].Length);
これにより、最初の行が単一のDimension配列にコピーされます。
i拡張メソッドを作成しました。パフォーマンスについて知りません。
public static class ExtensionMethods
{
public static string[] get1Dim(this string[,] RectArr, int _1DimIndex , int _2DimIndex )
{
string[] temp = new string[RectArr.GetLength(1)];
if (_2DimIndex == -1)
{
for (int i = 0; i < RectArr.GetLength(1); i++)
{ temp[i] = RectArr[_1DimIndex, i]; }
}
else
{
for (int i = 0; i < RectArr.GetLength(0); i++)
{ temp[i] = RectArr[ i , _2DimIndex]; }
}
return temp;
}
}
使用法
// we now have this funtionaliy RectArray[1, * ]
// -1 means ALL
string[] _1stRow = RectArray.get1Dim( 0, -1) ;
string[] _2ndRow = RectArray.get1Dim( 1, -1) ;
string[] _1stCol = RectArray.get1Dim( -1, 0) ;
string[] _2ndCol = RectArray.get1Dim( -1, 1) ;