2012-03-19 8 views
11
내가 더블 [,]에 다음 모음을 변환 할 필요가

으로 배열 목록을 변환하는 방법 : 목록에다차원 배열

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

모든 배열이 같은 길이. 가장 간단한 접근법 인 ret.ToArray()은 double [] []을 생성하며 이는 내가 원하는 것이 아닙니다. 물론 수동으로 새 배열을 만들고 루프에 숫자를 복사 할 수 있지만 더 우아한 방법이 있습니까?

편집 : 내 라이브러리는 .Net에서 개발되지 않은 다른 언어 인 Mathematica에서 호출됩니다. 나는 그 언어가 들쭉날쭉 한 배열을 사용할 수 있다고 생각하지 않는다. 다차원 배열을 반환해야합니다.

+1

은 2D 배열이 아닌 들쭉날쭉 한 배열을 원하는 것처럼 들리지만 모든 배열의 길이가 동일하기 때문에 이것이 필요한가요? – BrokenGlass

+1

다차원 배열이 필요한 코드를 변경하는 것이 더 편할 것입니다. – Jodrell

+0

아마 당신이 원하는 것을 정확하게 설명하고 원하는 이유를 설명하는 코드를 게시해야합니다. – Bernard

답변

18

이 작업을 수행하기 위해 프레임 워크에 아무 것도 내장되어 있지 않습니다. 심지어 Array.Copy도 실패합니다. 그러나, 반복하여 수행하는 코드를 작성하는 것은 쉽다 :

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

존 감사합니다! 나는 너의 책을 좋아한다. 내 코드가 비슷해 보이지만, 사용자 코드는 재사용이 가능합니다. –

2

당신이 (내가 더 좋은 방법을 생각할 수 없다)

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; 

편집에 복사하는 경우

SelectManyToArray을 사용하는 것보다 루프가 거의 빠릅니다.

언제 내가 골라 졌는지 알고 있습니다.

+0

Buffer.BlockCopy에 대해 배웠습니다. 감사! –

3

당신은 확장으로 다음을 수행 할 수

/// <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

널리 사용되는 것에 대한 확장 메서드를 만드는 경우 빌드가 느려집니다. –

+0

아니요, 정상적인 방법입니다 – Marcin

4

때문에 당신이 설명하고있는 상황에서이 작업을 수행하는 쉬운 방법이 목록에 double[] 배열을 중지 아무것도하는 것, 다른 크기 인에서 없다, 없다 2 차원 직사각형 배열과 호환되지 않는다. 그러나 모든 double[] 배열을 보장 할 수있는 위치에 같은 차원이있는 경우 다음과 같이, 당신은 당신의 2 차원 배열을 구성 할 수 있습니다 다음 double[]의 경우

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]; 
} 

이 런타임 오류가 발생합니다 목록의 배열은 첫 번째 배열보다 짧으며 배열 중 하나가 첫 번째 배열보다 큰 경우 데이터가 손실됩니다.

직사각형 배열에 들쭉날쭉 한 배열을 저장하려고 결정한 경우 "마법"값을 사용하여 해당 위치에 값이 없음을 나타낼 수 있습니다. 예를 들어 :

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; 
} 

사설 노트에, 나는 이것이 아주 나쁜 아이디어 ™ 생각; 직사각형 배열을 사용하려면 항상 Double.NaN을 확인해야합니다. 또한 Double.NaN을 배열의 합법적 인 값으로 사용하려면 어떻게해야합니까? 들쭉날쭉 한 배열이있는 경우에는 지그재그 배열로 두어야합니다.

+0

예, 목록의 double [] 배열이 다른 크기가되는 것을 막을 수있는 방법은 없습니다. 모든 배열의 크기는 같지만 .NET은 그렇지 않습니다. –