recorrer - ¿Cuál es la mejor manera de extraer una matriz unidimensional de una matriz rectangular en C#?
llenar un arreglo en c# (6)
Digamos que tengo una matriz de cadena rectangular, no una matriz dentada
string[,] strings = new string[8, 3];
¿Cuál es la mejor manera de extraer una matriz unidimensional de esta (ya sea una sola fila o una sola columna)? Puedo hacer esto con un bucle for, por supuesto, pero estoy esperando .NET tiene una forma más elegante integrada.
Puntos de bonificación por convertir la matriz de cadenas extraídas a una matriz de objetos.
Hice método de extensión. No sé sobre el rendimiento.
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;
}
}
uso
// 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) ;
LINQ es la respuesta
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++;
}
}
Las filas se pueden copiar fácilmente usando Array.Copia:
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);
Esto copiará la primera fila en la única matriz de dimensiones.
Me gustaría aclarar (dado el ejemplo y lo que se está preguntando).
Una matriz dentada es una matriz de matrices y se declara así:
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]" };
Frente a una matriz rectangular que se define como una única matriz que tiene múltiples dimensiones:
string[,] data = new string[3,3];
data[0,0] = "0,0";
data[0,1] = "0,1";
data[0,2] = "0,2";
...etc
Debido a esto, una matriz dentada es IQueryable / IEnumerable porque puede iterar sobre ella para recibir una matriz en cada iteración. Mientras que una matriz rectangular no es IQueryable / IEnumerable porque los elementos se direccionan en la dimensión completa (0,0 0,1..etc) por lo que no podrá utilizar Linq o cualquier función predefinida creada para Array en ese caso.
Aunque puede iterar sobre la matriz una vez (y lograr lo que quiere) así:
/// 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;
Espero que esto ayude :)
Para una matriz rectangular:
string[,] rectArray = new string[3,3] {
{"a", "b", "c"},
{"d", "e", "f"},
{"g", "h", "i"} };
var rectResult = rectArray.Cast<object>().ToArray();
Y para una variedad dentada:
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();
Puede lanzar una matriz de cadenas a una matriz de objetos trivialmente; ir por la otra dirección no funciona. Sin embargo, la extracción real tiene que usar un bucle for, por lo que puedo ver: Array.Copy
requiere que los rangos de origen y destino sean los mismos, y Buffer.BlockCopy
solo funciona para matrices de tipo de valor. Aunque parece extraño ...
Puede usar LINQ para agregar una fila o columna en una sola declaración, aunque será ineficiente (ya que construirá una lista internamente, luego tendrá que convertirla en una matriz; si lo hace usted mismo, puede preasignar la matriz al tamaño correcto y copia directamente).
Copiar una fila ( rowNum
es la fila que se va a copiar):
object[] row = Enumerable.Range(0, rowLength)
.Select(colNum => (object) stringArray[rowNum, colNum])
.ToArray();
Copiar una columna ( colNum
es la columna que se va a copiar):
object[] column = Enumerable.Range(0, columnLength)
.Select(rowNum => (object) stringArray[rowNum, colNum])
.ToArray();
Sin embargo, no estoy seguro de que esto sea realmente mejor / más simple que un ciclo foreach, especialmente si escribe un método ExtractRow
y un método ExtractColumn
y los ExtractColumn
utilizar.