2012-03-19 44 views
11

tôi cần phải chuyển đổi bộ sưu tập sau vào đôi [,]:Làm thế nào để chuyển đổi danh sách các mảng thành một mảng đa chiều

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

Tất cả các mảng trong danh sách có cùng độ dài. Cách tiếp cận đơn giản nhất, ret.ToArray(), tạo ra gấp đôi [] [], đó không phải là những gì tôi muốn. Tất nhiên, tôi có thể tạo một mảng mới theo cách thủ công và sao chép các số trong một vòng lặp, nhưng có cách nào thanh lịch hơn không?

Chỉnh sửa: thư viện của tôi được gọi bằng ngôn ngữ khác, Mathematica, chưa được phát triển trong .Net. Tôi không nghĩ rằng ngôn ngữ có thể sử dụng các mảng răng cưa. Tôi phải trả về một mảng đa chiều.

+1

nghe như bạn muốn một mảng * lởm chởm * không phải mảng 2D - bạn có chắc đó là yêu cầu của bạn vì tất cả các mảng có cùng độ dài không? – BrokenGlass

+1

nó có lẽ sẽ thanh lịch hơn để thay đổi mã cần mảng đa chiều. – Jodrell

+0

Có lẽ bạn nên đăng mã giải thích chính xác những gì bạn muốn và giải thích lý do bạn muốn theo cách đó. – Bernard

Trả lời

18

Tôi không tin rằng có bất kỳ thứ gì được tích hợp trong khung làm việc này - thậm chí Array.Copy không thành công trong trường hợp này. Tuy nhiên, thật dễ dàng để viết mã để làm điều đó bằng cách lặp:

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

Cảm ơn bạn Jon! Tôi là một fan hâm mộ lớn của cuốn sách của bạn. Mặc dù mã của tôi trông tương tự, nhưng mã của bạn có thể tái sử dụng nhiều hơn. –

2

Nếu bạn đang đi để sao chép (Tôi không thể nghĩ ra một cách tốt hơn)

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; 

EDIT

Tôi gần như một số vòng lặp nhất định thay vì sử dụng SelectManyToArray nhanh hơn.

Tôi biết khi nào tôi đã bị xiên.

+0

Tôi đã học về Buffer.BlockCopy. Cảm ơn! –

3

Bạn có thể làm sau khi mở rộng:

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

Nếu tôi tạo một phương pháp mở rộng cho một điều được sử dụng rộng rãi, điều đó sẽ làm chậm các bản dựng của tôi, phải không? –

+0

Không, nó cũng giống như phương pháp bình thường – Marcin

4

Không có cách nào dễ dàng để làm điều này bởi vì trong tình huống mà bạn đang mô tả, không có gì ngăn chặn sự double[] mảng trong danh sách là không bị các kích cỡ khác nhau, mà sẽ không tương thích với mảng hình chữ nhật hai chiều. Tuy nhiên, nếu bạn đang ở vị trí để đảm bảo double[] mảng tất cả đều có chiều tương tự, bạn có thể xây dựng mảng hai chiều của bạn như sau:

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

này sẽ tạo ra một lỗi thời gian chạy nếu một trong các double[] các mảng trong danh sách sẽ ngắn hơn danh sách đầu tiên và bạn sẽ mất dữ liệu nếu bất kỳ mảng nào lớn hơn mảng đầu tiên.

Nếu bạn thực sự quyết định lưu trữ một mảng răng cưa trong một mảng hình chữ nhật, bạn có thể sử dụng giá trị "ma thuật" để cho biết không có giá trị ở vị trí đó. Ví dụ:

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

Trên ghi chú biên tập, tôi nghĩ đây là ý tưởng rất tồi ™; khi bạn sử dụng mảng chữ nhật, bạn phải kiểm tra Double.NaN mọi lúc. Hơn nữa, nếu bạn muốn sử dụng Double.NaN làm giá trị hợp pháp trong mảng? Nếu bạn có một mảng lởm chởm, bạn chỉ nên để nó như là một mảng răng cưa.

+0

Có, không có gì ngăn chặn các mảng [] kép trong danh sách từ các kích thước khác nhau. Tôi biết rằng tất cả các mảng có cùng kích thước, nhưng .Net thì không. –

Các vấn đề liên quan