2010-11-16 28 views
10

Tôi muốn tạo một mảng n-chiều đôi. Tại thời gian biên dịch, không biết số thứ nguyên n.N-chiều Array

Tôi đã kết thúc định nghĩa mảng làm từ điển, với khóa là một mảng ints tương ứng với các trục khác nhau (vì vậy trong mảng 3 chiều, tôi sẽ cung cấp [5, 2, 3] để lấy gấp đôi tại (5, 2, 3) trong mảng

Tuy nhiên, tôi cũng cần nhập từ điển với số tăng gấp đôi từ (0, 0, ... 0) đến (m1, m2, ... mn) , trong đó m1 đến mn là chiều dài của mỗi trục

Ý tưởng ban đầu của tôi là tạo vòng lặp lồng nhau, nhưng tôi vẫn không biết mình cần bao nhiêu (1 cho mỗi thứ nguyên) 't làm điều này tại thời gian biên dịch.

Tôi ho pe Tôi đã xây dựng câu hỏi theo một cách dễ hiểu, nhưng cảm thấy tự do để yêu cầu tôi xây dựng các phần.

+0

Mảng sẽ được sử dụng như thế nào? –

+0

Nó sẽ được sử dụng trong các phép tính ngẫu nhiên của Factorial Markov, trong đó chúng ta có n lớp với các phân đoạn m trong mỗi phần. Sau đó chúng tôi muốn tạo một ma trận xác suất cho mỗi giá trị quan sát được, hoặc trong trường hợp các giá trị liên tục, hai ma trận, cho phương tiện và phương sai, cho mỗi giá trị quan sát được. – SimonPip

Trả lời

6

một followup nhanh chóng về vấn đề này:

Chúng tôi đã sử dụng phương pháp Array.CreateInstance với thành công, nhưng như ai đó đã dự đoán, nó khá kém hiệu quả và các vấn đề về khả năng đọc được tạo thêm.

Thay vào đó, chúng tôi đã phát triển một phương pháp, trong đó mảng n chiều được chuyển đổi thành mảng 1 chiều (bình thường).

public static int NDToOneD(int[] indices, int[] lengths) 
{ 
    int ID = 0; 
    for (int i = 0; i < indices.Length; i++) 
    { 
    int offset = 1; 
    for (int j = 0; j < i; j++) 
{ 
     offset *= lengths[j]; 
} 
    ID += indices[i] * offset; 
    } 
    return ID; 
} 

1DtoND(int[] indices, int[] arrayLengths) 
{ 
    int[] indices = new int[lengths.Length]; 
    for (int i = lengths.Length - 1; i >= 0; i--) 
    { 
    int offset = 1; 
    for (int j = 0; j < i; j++) 
    { 
     offset *= lengths[j]; 
    } 
    int remainder = ID % offset; 
    indices[i] = (ID - remainder)/offset; 
    ID = remainder; 
    } 
    return indices; 
} 

Đây là bản chất tổng quát về việc chuyển đổi tọa độ Descartes thành một số nguyên và ngược lại.

Thử nghiệm của chúng tôi không được chính thức hóa, vì vậy bất kỳ tốc độ nào chúng tôi đã đạt được đều hoàn toàn giai thoại, nhưng đối với máy của tôi, nó tăng tốc 30-50%, tùy thuộc vào kích thước mẫu và khả năng đọc mã đã được cải thiện bằng một biên độ rộng.

Hy vọng điều này sẽ giúp bất kỳ ai tình cờ gặp phải câu hỏi này.

0

Tại sao bạn không chỉ sử dụng mảng đa chiều: double[,,] array = new double[a,b,c]? Tất cả các phần tử mảng được tự động khởi tạo là 0.0 cho bạn.

Ngoài ra, bạn có thể sử dụng một mảng lởm chởm double[][][], nhưng mỗi tiểu mảng sẽ cần phải được khởi tạo trong một vòng lặp for:

int a, b, c; 
double[][][] array = new double[a][][]; 

for (int i=0; i<a; i++) { 
    double[i] = new double[b][]; 

    for (int j=0; j<b; j++) { 
     double[i][j] = new double[c]; 
    } 
} 

EDIT: đã không nhận ra số kích thước được thời gian chạy. Đã thêm câu trả lời khác ở trên.

+1

Vì tôi không biết số thứ nguyên ở thời gian biên dịch.Xin lỗi, nếu ví dụ (5, 2, 3) làm bạn bối rối. Nó cũng có thể là (5, 3, 2, 8, 7, 6, 32). :) – SimonPip

15

Để tạo một mảng n chiều, bạn có thể sử dụng Array.CreateInstance phương pháp:

Array array = Array.CreateInstance(typeof(double), 5, 3, 2, 8, 7, 32)); 

array.SetValue(0.5d, 0, 0, 0, 0, 0, 0); 
double val1 = (double)array.GetValue(0, 0, 0, 0, 0, 0); 

array.SetValue(1.5d, 1, 2, 1, 6, 0, 30); 
double val2 = (double)array.GetValue(1, 2, 1, 6, 0, 30); 

Để cư mảng, bạn có thể sử dụng Rank tài sản và GetLength phương pháp để trả lại chiều dài của kích thước hiện tại, sử dụng một vài lồng nhau cho vòng để làm một O (n^m) algo (cảnh báo - chưa được kiểm tra):

private bool Increment(Array array, int[] idxs, int dim) { 
    if (dim >= array.Rank) return false; 

    if (++idxs[idxs.Length-dim-1] == array.GetLength(dim)) { 
     idxs[idxs.Length-dim-1] = 0; 
     return Increment(array, idxs, dim+1); 
    } 
    return true; 
} 

Array array = Array.CreateInstance(typeof(double), ...); 
int[] idxs = new int[array.Rank]; 
while (Increment(array, idxs, 0)) { 
    array.SetValue(1d, idxs); 
}