1

for example

 for (int i=0;i<100;i++)
   for (int j=0;j<100;j++)
     for (int k=0;k<100;k++)
       for (int l=0;l<100;l++)
         for (int m=0;m<100;m++)
  {
     DoSth(myArray[i,j,k,l,m]);
  }

I tried to convert 5dimensional myArray into int[][][][][] myJaggedArray, it is still slow.

Is there any way I can improve it? Note: the most overhead comes from the multi dimensional array index lookup

There is one ugly way i can think of: (e.g. 2 nested loop)

for (int i=0;i<100;i++)
 {
   var tmp = myJaggedArray[i];
   {
     for (int j=0;j<100;j++)
     {
      DoSth(tmp[j]);
      }
   }
 }
colinfang
  • 20,909
  • 19
  • 90
  • 173
  • 1
    How to optimize it depends on what you are doing this for. – Kendall Frey Mar 14 '12 at 16:48
  • If you truly need a 5dimensional array and need to access every member of said array then you will end up with this same amount of calls no matter the implementation. A custom iterator would at least prevent you from having to use 5 nested for loops multiple times in your code every time you need to loop through the values. – jzworkman Mar 14 '12 at 16:52
  • Your edits have *completely* changed the question... without any comment or indication that you've done so. – Jon Skeet Mar 14 '12 at 17:03
  • @JonSkeet: sry, I am still thinking of a best way to abstract my problem. It is reverted back now – colinfang Mar 14 '12 at 17:05
  • @colinfang: Just when I've edited my answer to take account of the changes... I'm afraid when you just keep changing it with no actual context (like the size of the array, or what you're trying to achieve) there's not a lot of point in me continuing. Hopefully the answer I've already provided will help, but if not, ping me a comment when you've made the question more answerable (and are content not to change it any further). – Jon Skeet Mar 14 '12 at 17:08

4 Answers4

3

Simply put: don't use a multi-dimensional array if you can help it and if you really need the speed. They're significantly slower to access than single-dimensional arrays. I don't know how much difference there is between "rank 2" and "rank 5", but the difference between vectors (always 0-based, single-dimensional) and arrays (arbitrary base, can be multi-dimensional) if pretty big.

It looks like you're iterating over the whole array in the obvious order, so just keep it as a single-dimensional array instead. Mind you, as if this is an int array that's 40GB of data. Do you really have that much data, and is it all in physical memory rather than swapping?

EDIT: Okay, now that you've completely changed the question... you can start by not refetching a[i], b[j] on every iteration (which could be having severe cache implications):

for (int i = 0; i < 100; i++)
{
    int ai = a[i];
    for (int j = 0; j < 100; j++)
    {
        int bj = b[j];
        for (int k = 0; k < 100; k++)
        {
            int ck = c[k];
            for (int l = 0; l < 100; l++)
            {
                dl = d[l];
                for (int m = 0; m < 100; m++)
                {
                    int em = e[m];
                    DoSomething(myArray[ai, bj, ck, dl, em]);
                }
            }
        }
    }
}

Using a jagged array as per your question would also help, but could have significant memory implications. Another alternative is to have a single-dimensional array, and work out the "base index" at each level of your loop.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Infact, there is no apparently ways to optimise array acess, OP concerns about, but *iteration* flow. – Tigran Mar 14 '12 at 16:54
  • 3
    When Jon answers a question I was going to respond to, it feels like someone just said over the radio "Good morning, gentlemen, the temperature is 110 degrees." :-) I would just add to ensure that you access your flattened array in row major order. That can make a huge difference in performance due to elements being next to each other in cache. http://en.wikipedia.org/wiki/Row-major_order – Eric J. Mar 14 '12 at 16:57
1

Give the Jitter a chance to optimize:

for (int i=0; i < myArray.GetLength(0);i++)
   for (int j=0; j < myArray.GetLength(1);j++)
     for (int k=0; k < myArray.GetLength(2);k++)
       for (int l=0; l < myArray.GetLength(3);l++)
         for (int m=0; m < myArray.GetLength(4);m++)
  {
     DoSth(myArray[i,j,k,l,m]);
  }

This will speed up a jagged array more than this case.

And at the very least it's easier to maintain.


The real speed up case:

int[][][] myArray = ...; // create it
....


for (int i=0; i < myArray.Length; i++)
{
   subArray1 = myArray[i];
   for (int j=0; j < subArray1.Length; j++)
   {
     subArray2 = subArray2[j];
     for (int k=0; k < subArray2.Length; k++)
     {
        subArray2[k] = ...
     }
   }
}
H H
  • 263,252
  • 30
  • 330
  • 514
  • could u provide some keywords i can search for this technique? i am quite interested in it. – colinfang Mar 14 '12 at 17:21
  • It has to do with range-checking. Which is your real problem, not the lookup. Here is [one (of many) SO questions](http://stackoverflow.com/q/1986989/60761). – H H Mar 14 '12 at 17:24
  • however, from my reading here http://blogs.msdn.com/b/clrcodegeneration/archive/2009/08/13/array-bounds-check-elimination-in-the-clr.aspx multi-dimensional array won't eliminate range check – colinfang Mar 15 '12 at 16:42
  • Correct, it is more aimed at the jagged arrays. I copied some code that was available. Will edit. – H H Mar 15 '12 at 18:03
0

May be

foreach (int x in myArray) {
    DoSth(x);
}

As Jon Skeet says, your array is HUGE! If it contains mainly nulls, you should consider an alternative approach. You could use a dictionary to store the values.

var dict = new Dictionary<long,int>();

if (value != 0) {
    long index = (((i * 100 + j) * 100 + k) * 100 + l) * 100 + m;
    dict[index] = value;
}

It would be best to use a helper function to calculate the index

public long Index(int i, int j, int k, int l, int m)
{
    return (((i * 100 + j) * 100 + k) * 100 + l) * 100 + m;
}

 

dict[Index(i,j,k,l,m)] = value;

int result;
if (dict.TryGetValue(Index(i,j,k,l,m), out result)) {
    DoSth(result);
}

Or

foreach (int value in dict.Values) {
    DoSth(value);
}
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
0

If your array is sparse (many zeroes), a dictionary with Tuple as key will be much faster:

var dict = new Dictionary<Tuple<int, int, int, int int>, int>();

// Add element
dict[new Tuple(i,j,k,l,m)] = value;

// Get element
value = dict[new Tuple(i,j,k,l,m)];

// Traverse
foreach(var kv in dict)
{
     // You can always get the indexes if you need to
     int i = kv.Key.Item1;
     int j = kv.Key.Item2;
     int k = kv.Key.Item3;
     int l = kv.Key.Item4;
     int m = kv.Key.Item5;

     // ...Or do something
     DoSomething(kv.Value);
}
Diego
  • 18,035
  • 5
  • 62
  • 66