2011-09-06 19 views
8

Asumamos que tenemos una matriz escalonadaoperaciones de matriz con matriz n-dimensional utilizando LINQ (C#)

int[][] a = { new[] { 1, 2, 3, 4 }, new[] { 5, 6, 7, 8 }, new[] { 9, 10, 11, 12 } }; 

Para obtener una suma de segunda fila y la suma de la segunda columna, se puede escribir ambas líneas de código, respectivamente:

int rowSum = a[1].Sum(); 
int colSum = a.Select(row => row[1]).Sum(); 

Pero si tenemos la definición de la matriz de 2 dimensiones

int[,] a = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; 

el código antes citado no funcionará debido a errores compiller:

Error 1 Wrong number of indices inside []; expected 2 
Error 2 'int[*,*]' does not contain a definition for 'Select' and no extension method 'Select' accepting a first argument of type 'int[*,*]' could be found (are you missing a using directive or an assembly reference?) 

Por lo tanto, la pregunta: ¿Cómo utilizar métodos de LINQ con matrices n-dimensional, pero no los irregulares? ¿Y dónde es un método para convertir la matriz rectangular en irregular?

P.S. Traté de encontrar la respuesta en la documentación, pero sin resultado.

+0

matrices multidimensionales no son verdad (ampliamente) apoyada en C# :-( – xanatos

Respuesta

15

LINQ to Objects se basa en IEnumerable<T> Interface, es decir, una secuencia de valores unidimensional. Esto significa que no se combina bien con las estructuras de datos en n dimensiones como las matrices no dentadas, aunque es posible.

Puede generar la secuencia unidimensional de enteros que índice en la n-dimensional array:

int rowSum = Enumerable.Range(0, a.GetLength(1)).Sum(i => a[1, i]); 

int colSum = Enumerable.Range(0, a.GetLength(0)).Sum(i => a[i, 1]); 
+1

1: enfoque interesante –

3

Sobre su pregunta "¿Cómo utilizar métodos de LINQ con matrices n-dimensional":

Usted no puede usar la mayoría de los métodos LINQ con una matriz dimensional, ya que dicha matriz solo implementa IEnumerable pero no IEnumerable<T> y la mayoría de los métodos de extensión LINQ son métodos de extensión para IEnumerable<T>.

Acerca de la otra pregunta: Consulte la respuesta del dtb.

3

Para añadir a la solución de DTB, de manera más general de iterar sobre todos los elementos de la matriz sería:

int[,] b = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; 

var flattenedArray = Enumerable.Range(0, b.GetLength(0)) 
        .SelectMany(i => Enumerable.Range(0, b.GetLength(1)) 
         .Select(j => new { Row = i, Col = j })); 

Y ahora:

var rowSum2 = flattenedArray.Where(t => t.Row == 1).Sum(t => b[t.Row, t.Col]); 
var colSum2 = flattenedArray.Where(t => t.Col == 1).Sum(t => b[t.Row, t.Col]); 

Por supuesto, esto es ultra-derrochador como estamos creando tuplas de coordenadas incluso para los artículos que terminaremos filtrando con Where, pero si no sabes cuáles serán los criterios de selección de antemano, este es el camino a seguir (o no, esto parece más un ejercicio) de algo que quisieras hacer en la práctica).

También me puedo imaginar cómo podría extenderse esto para arreglos de cualquier rango (no solo 2D) utilizando un lambda recursivo y algo así como Tuple, pero que se cruza con el territorio del masoquismo.

1

La matriz 2D no tiene ninguna forma integrada de iterar sobre una fila o columna. Sin embargo, no es demasiado difícil crear tu propio método. Vea esta clase para una implementación que obtiene un enumerable para fila y columna.

public static class LINQTo2DArray 
{ 
    public static IEnumerable<T> Row<T>(this T[,] Array, int Row) 
    { 
     for (int i = 0; i < Array.GetLength(1); i++) 
     { 
      yield return Array[Row, i]; 
     } 
    } 
    public static IEnumerable<T> Column<T>(this T[,] Array, int Column) 
    { 
     for (int i = 0; i < Array.GetLength(0); i++) 
     { 
      yield return Array[i, Column]; 
     } 
    } 
} 

También puede aplanar la matriz mediante a.Cast<int>() pero lo haría a continuación, suelta toda la información sobre columnas/filas

-1

El más simple LINQ único enfoque que puedo ver como hacer este tipo de operaciones de fila y columna en una matriz bidimensional es definir las siguientes búsquedas:

var cols = a 
    .OfType<int>() 
    .Select((x, n) => new { x, n, }) 
    .ToLookup(xn => xn.n % a.GetLength(1), xn => xn.x); 

var rows = a 
    .OfType<int>() 
    .Select((x, n) => new { x, n, }) 
    .ToLookup(xn => xn.n/a.GetLength(1), xn => xn.x); 

Ahora simplemente puede hacer esto:

var firstColumnSum = cols[0].Sum(); 

En cuanto a n-dimensional, es demasiado doloroso ... Lo siento.

0

Una manera más simple está haciendo, como a continuación

var t = new List<Tuple<int, int>>(); 
int[][] a = t.Select(x => new int[]{ x.Item1, x.Item2}).ToArray(); 
Cuestiones relacionadas