2012-03-19 22 views
11

Necesito convertir la siguiente colección doble [,]:Cómo lista de matrices convertir en una matriz multidimensional

var ret = new List<double[]>(); 

Todas las matrices de la lista tienen la misma longitud. El enfoque más simple, ret.ToArray(), produce el doble [] [], que no es lo que quiero. Por supuesto, puedo crear una nueva matriz manualmente y copiar números en un bucle, pero ¿hay una manera más elegante?

Editar: mi biblioteca se invoca desde un idioma diferente, Mathematica, que no se ha desarrollado en .Net. No creo que el lenguaje pueda utilizar arreglos dentados. Tengo que devolver una matriz multidimensional.

+1

suena como si quisiera una matriz * dentada * no una matriz 2D: ¿está seguro de que es su requisito ya que todas las matrices tienen la misma longitud? – BrokenGlass

+1

probablemente sería más elegante cambiar el código que necesita la matriz multidimensional. – Jodrell

+0

Quizás deba publicar un código que explique exactamente lo que desea y explique por qué lo desea de esa manera. – Bernard

Respuesta

18

No creo que haya nada incorporado en el marco para hacer esto, incluso en este caso falla Array.Copy. Sin embargo, es fácil escribir el código para hacerlo por el bucle:

using System; 
using System.Collections.Generic; 

class Test 
{ 
    static void Main() 
    { 
     List<int[]> list = new List<int[]> 
     { 
      new[] { 1, 2, 3 }, 
      new[] { 4, 5, 6 }, 
     }; 

     int[,] array = CreateRectangularArray(list); 
     foreach (int x in array) 
     { 
      Console.WriteLine(x); // 1, 2, 3, 4, 5, 6 
     } 
     Console.WriteLine(array[1, 2]); // 6 
    } 

    static T[,] CreateRectangularArray<T>(IList<T[]> arrays) 
    { 
     // TODO: Validation and special-casing for arrays.Count == 0 
     int minorLength = arrays[0].Length; 
     T[,] ret = new T[arrays.Count, minorLength]; 
     for (int i = 0; i < arrays.Count; i++) 
     { 
      var array = arrays[i]; 
      if (array.Length != minorLength) 
      { 
       throw new ArgumentException 
        ("All arrays must be the same length"); 
      } 
      for (int j = 0; j < minorLength; j++) 
      { 
       ret[i, j] = array[j]; 
      } 
     } 
     return ret; 
    } 

} 
+0

Gracias Jon! Soy un gran fan de tu libro. Aunque mi código es similar, el tuyo es mucho más reutilizable. –

2

Si va a copiar (no puedo pensar en una mejor manera)

var width = ret[0].length; 
var length = ret.Count; 
var newResult = new double[width, length] 
Buffer.BlockCopy(ret.SelectMany(r => r).ToArray(), 
        0, 
        newResult, 
        0, 
        length * width); 
return newResult; 

EDITAR

Estoy casi seguro de bucle en lugar de utilizar SelectMany y ToArray es más rápido.

Sé cuando he sido maltratado.

+0

Me enteré de Buffer.BlockCopy. ¡Gracias! –

3

Usted puede hacer siguiente como extensión:

/// <summary> 
    /// Conerts source to 2D array. 
    /// </summary> 
    /// <typeparam name="T"> 
    /// The type of item that must exist in the source. 
    /// </typeparam> 
    /// <param name="source"> 
    /// The source to convert. 
    /// </param> 
    /// <exception cref="ArgumentNullException"> 
    /// Thrown if source is null. 
    /// </exception> 
    /// <returns> 
    /// The 2D array of source items. 
    /// </returns> 
    public static T[,] To2DArray<T>(this IList<IList<T>> source) 
    { 
     if (source == null) 
     { 
      throw new ArgumentNullException("source"); 
     } 

     int max = source.Select(l => l).Max(l => l.Count()); 

     var result = new T[source.Count, max]; 

     for (int i = 0; i < source.Count; i++) 
     { 
      for (int j = 0; j < source[i].Count(); j++) 
      { 
       result[i, j] = source[i][j]; 
      } 
     } 

     return result; 
    } 
+0

Si creo un método de extensión para una cosa ampliamente utilizada, eso ralentizará mis compilaciones, ¿no? –

+0

No, es solo como el método normal – Marcin

4

No hay manera fácil de hacer esto debido a que en la situación que describes, no hay nada que impida que los double[] matrices en la lista de ser diferentes tamaños, lo que haría ser incompatible con una matriz rectangular bidimensional. Sin embargo, si se encuentra en la posición de garantizar los double[] matrices todos tienen la misma dimensión, puede construir su matriz bidimensional de la siguiente manera:

var arr = new double[ret.Count(),ret[0].Count()]; 

for(int i=0; i<ret.Count(); i++) { 
    for(int j=0; j<ret[i].Count(); j++) 
    arr[i,j] = ret[i][j]; 
} 

Esto producirá un error en tiempo de ejecución si cualquiera de los double[] las matrices en la lista son más cortas que la primera, y perderá datos si alguna de las matrices es más grande que la primera.

Si realmente está decidido a almacenar una matriz dentada en una matriz rectangular, puede usar un valor "mágico" para indicar que no hay ningún valor en esa posición. Por ejemplo:

var arr = new double[ret.Count(),ret.Max(x=>x.Count())]; 

for(int i=0; i<ret.Count(); i++) { 
    for(int j=0; j<arr.GetLength(1); j++) 
    arr[i,j] = j<ret[i].Count() ? ret[i][j] : Double.NaN; 
} 

En una nota editorial, creo que esto es una idea muy mala ™; Cuando vaya a utilizar la matriz rectangular, debe verificar Double.NaN todo el tiempo. Además, ¿qué pasaría si quisiera usar Double.NaN como un valor legítimo en la matriz? Si tienes una matriz dentada, solo debes dejarla como una matriz dentada.

+0

Sí, no hay nada que detenga los arreglos dobles [] de la lista de tamaños diferentes. Sé que todas las matrices tienen los mismos tamaños, pero .Net no. –

Cuestiones relacionadas