none
How do I enumerate all indices to a multi-dimensional array? RRS feed

  • Question

  • I would like to fill a multi-dimensional array A with values of function f.  I am tempted to write

    foreach (int[] X in A. GetIndices ()) A .SetValue (X, f (X));
    But I cannot find anything resembling Array .GetIndices.  Please help.


    Christopher Yeleighton

    Friday, March 7, 2014 10:28 AM

Answers

  • "cannot nest for loops when the nesting depth is arbitrary."

    I see, you don't know the number of dimensions at compile time. Indeed, there's nothing like the GetIndices function you're looking for. But it's quite simple to create something like this:

    static void Main() {
        var a = Array.CreateInstance(typeof(int), new[] { 2, 3, 4 });
    
        var rand = new Random();
    
        foreach (var indices in GetIndices(a))
            a.SetValue(rand.Next(), indices);
    }
    
    static IEnumerable<int[]> GetIndices(Array a) {
        var indices = new int[a.Rank];
    
        for (bool done = false; !done; ) {
            yield return indices;
    
            for (int i = indices.Length - 1; i >= 0; i--) {
                indices[i] = (indices[i] + 1) % (a.GetUpperBound(i) + 1);
    
                if (indices[i] != 0)
                    break;
    
                if (i == 0)
                    done = true;
            }
        }
    }
    

    • Marked as answer by yecril Friday, March 7, 2014 12:38 PM
    Friday, March 7, 2014 11:35 AM
    Moderator

All replies

  • http://msdn.microsoft.com/en-us/library/2h3zzhdw.aspx

    Mark Answered, if it solves your question and Vote if you found it helpful.
    Rohit Arora

    Friday, March 7, 2014 10:33 AM
  • By multi-dimensional array do you mean something like "new int[2, 3]"? Or perhaps something like "new int[2][]" which is called "jagged array" in C#?

    Something like "foreach (int[] x in a)" would work for a jagged array but not for a multidimensional array. With multi-dimensional arrays you cannot somehow extract an individual row from the array so you'd need to pass the array and the row index to function f if it really needs a row as it appear from your example.

    Friday, March 7, 2014 10:42 AM
    Moderator
  • Use a List<> object.

                List<List<int>> input = new List<List<int>> { new List<int> { 9, 99 }, new List<int> { 3, 33 }, new List<int> { 5, 55 } };
                var output = input.Select(x => x.Select(y => y).ToArray()).ToArray();


    jdweng

    Friday, March 7, 2014 10:49 AM
  • You cannot set values using foreach and you cannot nest for loops when the nesting depth is arbitrary.

    Christopher Yeleighton

    Friday, March 7, 2014 10:54 AM
  • I mean something like Array.CreateInstance.  Note that the function f does not access the array, it computes the value to be inserted at each given index.


    Christopher Yeleighton

    Friday, March 7, 2014 10:57 AM
  • Hmm, so that looks like a multidimensional array. Have you seen the example on that page? It does fill such an array with values computed based on indices. You could simply substitute "Convert.ToString(i) + j + k + l" with a call to your function f. Am I missing something?
    Friday, March 7, 2014 11:03 AM
    Moderator
  • "cannot nest for loops when the nesting depth is arbitrary."

    I see, you don't know the number of dimensions at compile time. Indeed, there's nothing like the GetIndices function you're looking for. But it's quite simple to create something like this:

    static void Main() {
        var a = Array.CreateInstance(typeof(int), new[] { 2, 3, 4 });
    
        var rand = new Random();
    
        foreach (var indices in GetIndices(a))
            a.SetValue(rand.Next(), indices);
    }
    
    static IEnumerable<int[]> GetIndices(Array a) {
        var indices = new int[a.Rank];
    
        for (bool done = false; !done; ) {
            yield return indices;
    
            for (int i = indices.Length - 1; i >= 0; i--) {
                indices[i] = (indices[i] + 1) % (a.GetUpperBound(i) + 1);
    
                if (indices[i] != 0)
                    break;
    
                if (i == 0)
                    done = true;
            }
        }
    }
    

    • Marked as answer by yecril Friday, March 7, 2014 12:38 PM
    Friday, March 7, 2014 11:35 AM
    Moderator
  • Thank you. Your function works only if the lower bound is 0 but it will be easy to fix.

    Christopher Yeleighton

    Friday, March 7, 2014 12:42 PM