2015-11-23 49 views
1

請參閱下面的代碼段。訪問具有一維索引的多維數組的方式是什麼? Foreach可以做到。是的,我知道,IEnumerable和yield是不一樣的索引。我應該使用一個foreach並創建一個新的數組?或者我可以在不創建新陣列的情況下執行此操作?使用一維索引訪問多維數組

int[,] myArray = new int[2, 2]; 
    myArray[0,0] = 1; 
    myArray[1,1] = 2; 
    myArray[0,0] = 3; 
    myArray[1,1] = 4; 
    foreach (var value in myArray) 
    { 
     Console.Write(value); 
    } 

    var valueAtIndex = myArray[2]; //Won't compile, error: Wrong number of indices inside []; expected 2 
+2

你的期望是什麼?你認爲'myArray [2]'可以返回什麼?你有什麼確切的問題? –

+2

*爲什麼*你想使用這樣的索引?你想解決什麼問題?您是否試圖將用另一種語言編寫的程序轉換爲C#?無論你正在嘗試做什麼可能已經實現 –

+0

我需要應用一個操作多維數組的維度可以不同,並且值類型可能會更新。 –

回答

2

如果你想不只是讀出的值,而且將它們以相同的順序爲foreach遍歷數組,你可以使用下面的一般索引類:

public class ArrayIndexer 
{ 
    readonly int totalLength; 
    readonly int lastIndexLength; 
    readonly int[] lengths; 
    readonly int[] lowerBounds; 
    int current; 
    readonly int[] currentZeroBased; 

    public ArrayIndexer(int[] lengths, int[] lowerBounds) 
    { 
     lastIndexLength = lengths[lengths.Length - 1]; 
     totalLength = lengths[0]; 
     for (int i = 1; i < lengths.Length; i++) 
     { 
      totalLength *= lengths[i]; 
     } 
     this.lengths = lengths; 
     this.lowerBounds = lowerBounds; 
     currentZeroBased = new int[lengths.Length]; 
     current = -1; 
    } 

    public bool MoveNext() 
    { 
     current++; 
     if (current != 0) 
     { 
      int currLastIndex = current % lastIndexLength; 
      currentZeroBased[currentZeroBased.Length - 1] = currLastIndex; 
      if (currLastIndex == 0) 
      { 
       for (int i = currentZeroBased.Length - 2; i >= 0; i--) 
       { 
        currentZeroBased[i]++; 
        if (currentZeroBased[i] != lengths[i]) 
         break; 
        currentZeroBased[i] = 0; 
       } 
      } 
     } 
     return current < totalLength; 
    } 

    public int[] Current 
    { 
     get 
     { 
      int[] result = new int[currentZeroBased.Length]; 
      for (int i = 0; i < result.Length; i++) 
      { 
       result[i] = currentZeroBased[i] + lowerBounds[i]; 
      } 
      return result; 
     } 
    } 
} 

而且你可以使用它像這樣設置整個陣列:

int[,] myArray = new int[2, 2]; 
ArrayIndexer arrayIndexer = new ArrayIndexer(new[] {2, 2}, new[] {0, 0}); 
int i = 0; 
while (arrayIndexer.MoveNext()) 
{ 
    myArray.SetValue(++i, arrayIndexer.Current); 
} 
3

如果一維索引你的意思是周圍的多維數組的行包,以從上到下從左到右的索引,那麼你可以用這個公式計算,從它xy

x = index % width 
y = index/width 
0

如何從另一端接近它?

int rows=2, cols=2; 
int[] myArray = new int[rows*cols]; 

public void setMyArray(int[] myArray, int x, int y, int value) 
{ 
    myArray[(y)*cols + x] = value; 
} 

setMyArray(0,0,1); 
setMyArray(0,1,2); 
setMyArray(1,0,3); 
setMyArray(1,1,4); 
0

至於枚舉器,它非常簡單 - 它只允許順序訪問。在內部,它包含一系列索引並逐一遞增。它不會使用任何破解來使數組變成一維或任何東西 - 這將是對框架保證的醜惡違反。而且也沒有收益率,這是很久以前寫出來的:)

你可以自己寫這樣的黑客,當然,使用unsafe代碼。但是,這是一個非常糟糕的主意。你不需要知道如何在內存中組織這些數組 - 這是運行時的實現細節。不要。

相反,找出一個合理的尋址模式。如果有一個單一的索引是有意義的,爲什麼這個數組首先是多維的?如果數組是多維的是合理的,那麼你爲什麼要以單維方式訪問它?

如果確實有意義,出於某種原因,您可能希望圍繞某個內部數組創建自己的包裝類,而不是僅使用數組。它是那樣簡單

public class DualAccessArray<T> 
{ 
    private readonly T[,] _internalArray; 
    private readonly int _width; 
    private readonly int _height; 

    public DualAccessArray(int width, int height) 
    { 
    _width = width; 
    _height = height; 
    _internalArray = new T[width, height]; 
    } 

    public T this[long index] 
    { 
    get { return _internalArray[index/_width, index % _width]; } 
    set { _internalArray[index/_width, index % _width] = value; } 
    } 

    public T this[int x, int y] 
    { 
    get { return _internalArray[x, y]; } 
    set { _internalArray[x, y] = value; } 
    } 
} 

然後您可以使用像

var ar = new DualAccessArray<string>(10, 10); 
ar[15] = "Hi!"; 
Console.WriteLine(ar[1, 5]); 

可以適應這個您的需求。例如,尋找不同類型的尋址和內存佈局可能更有意義,將陣列設置爲單維可能是有意義的,您可能想要包裝現有的陣列......這完全取決於您實際上正在努力去做。

0

的foreach可以做到這一點

不,它不能。真的沒有比喻。

由於多維數組事實上是一個具有多個維度的數組,因此您有三個選項。

  1. 停止使用多維數組。如果這種操作占主導地位,那麼陣列(「鋸齒狀陣列」)可能會更好地匹配你想要的。

  2. 忽略數組的細節並將指針用於內存。最好避免,如果不是非常必要的話。

  3. 只需使用兩個索引。你可以很容易地找到其他指標的範圍,所以做到這一點。

以下操作將在二維數組上運行,並且當給定第一個索引的值時,將遍歷該索引的所有值。

public static IEnumerable<T> GetRow<T>(this T[,] array, int index) 
{ 
    int last = array.GetUpperBound(1); 
    for(int idx = array.GetLowerBound(1); idx <= last; ++idx) 
    yield return array[index, idx]; 
} 
0

在這裏回答標題。假設我們需要訪問具有一維索引的任意維數組。

var test = new [,,,] 
{ 
    { 
     { 
      { 00, 01, 02 }, { 03, 04, 05 }, { 06, 07, 08 } 
     }, 
     { 
      { 09, 10, 11 }, { 12, 13, 14 }, { 15, 16, 17 } 
     }, 
     { 
      { 18, 19, 20 }, { 21, 22, 23 }, { 24, 25, 26 } 
     } 
    }, 
    { 
     { 
      { 27, 28, 29 }, { 30, 31, 32 }, { 33, 34, 35 } 
     }, 
     { 
      { 36, 37, 38 }, { 39, 40, 41 }, { 42, 43, 44 } 
     }, 
     { 
      { 45, 46, 47 }, { 48, 49, 50 }, { 51, 52, 53 } 
     } 
    } 
}; 

Func<int, IEnumerable<int>, IEnumerable<int>> unwrapLinearIndex = (linidx, bounds) => 
    bounds.Select((b, i) => bounds.Take(i).Aggregate(linidx, (acc, bnd) => acc/bnd) % b); 

// Reverse() to enumerate innermost dimensions first 
var testBounds = new int[test.Rank].Select((_, d) => test.GetUpperBound(d) + 1).Reverse().ToArray(); 

for (int i = 00; i < test.Length; i++) 
{ 
    var indexes = unwrapLinearIndex(i, testBounds).Reverse().ToArray(); 
    Console.Write($"{test.GetValue(indexes)} "); 
} 

輸出是0 1 2 3 4... 53