tags:

views:

2806

answers:

8

Hello everyone,

My following code has compile error,

Error 1 Cannot implicitly convert type 'TestArray1.Foo[,,*]' to 'TestArray1.Foo[][][]' C:\Users\lma\Documents\Visual Studio 2008\Projects\TestArray1\TestArray1\Program.cs 17 30 TestArray1

Does anyone have any ideas? Here is my whole code, I am using VSTS 2008 + Vista 64-bit.

namespace TestArray1
{
    class Foo
    {    
    }

    class Program
    {
        static void Main(string[] args)
        {
            Foo[][][] foos = new Foo[1, 1, 1];

            return;
        }
    }
}

EDIT: version 2. I have another version of code, but still has compile error. Any ideas?

Error   1 Invalid rank specifier: expected ',' or ']' C:\Users\lma\Documents\Visual Studio 2008\Projects\TestArray1\TestArray1\Program.cs 17 41 TestArray1
Error   2 Invalid rank specifier: expected ',' or ']' C:\Users\lma\Documents\Visual Studio 2008\Projects\TestArray1\TestArray1\Program.cs 17 44 TestArray1


namespace TestArray1
{
    class Foo
    {    
    }

    class Program
    {
        static void Main(string[] args)
        {
            Foo[][][] foos = new Foo[1][1][1];

            return;
        }
    }
}

EDIT: version 3. I think I want to have a jagged array. And after learning from the fellow guys. Here is my code fix, and it compile fine in VSTS 2008. What I want is a jagged array, and currently I need to have only one element. Could anyone review whether my code is correct to implement my goal please?

namespace TestArray1
{
    class Foo
    {    
    }

    class Program
    {
        static void Main(string[] args)
        {
            Foo[][][] foos = new Foo[1][][];
            foos[0] = new Foo[1][];
            foos[0][0] = new Foo[1];
            foos[0][0][0] = new Foo();
            return;
        }
    }
}

thanks in advance, George

+3  A: 

Make up your mind :)

You either want:

Foo[,,] foos = new Foo[1, 1, 1];

or:

Foo[][][] foos = new Foo[1][1][1];
Jon Grant
Hi Jon, what is the differences between define foos as [,,] or [][][]? I think they are the same! :-)
George2
Second one is jagged, meaning for each row the next dimension can have varying sized arrays.
AaronLS
The first one is a three-dimensional array, that is, one contiguous memory block holding all elements. The other syntax is an array of arrays of arrays, which has very bad memory locality and furthermore, the inidividual ararys can be differently sized, too. It's all up to what exactly you want
Joey
@Jon/@aaronls/@Johannes, I have followed your comments, but still has compile error. Please check my code version 2 in my original post for my new code and compile error. Any ideas or comments?
George2
new Foo[1][1][1] is invalid. You have to do new Foo[1][][] and then populate each sub-array.
Keith
@Keith, I have followed your comments to add version 3 of my code. Could you help to review whether my code is correct to implement my goal please? Thanks!
George2
+1  A: 

Depends on whether you want them to be jagged or not:

//makes a 5 by 4 by 3 array:

string[,,] foos = new string[5,4,3];

http://msdn.microsoft.com/en-us/library/aa288453(VS.71).aspx

Oh and here is initializing values:

    char[, ,] blah = new char[2, 2, 2] { 
        {{ '1', '2' }, { '3', '4' }},
        {{ '5', '6' }, { '7', '8' }}
         };

Note that this will not work:

Foo[][][] foos = new Foo[1][1][1];

Because you are using the jagged array syntax, which does not let you define the size of nested arrays. Instead use do this:

Foo[,,] foos = new Foo[1][1][1];  //1 by 1 by 1

or this

Foo[][][] foos = new Foo[1][][];  //1 array allowing two nested levels of jagged arrays
foos[0] = new Foo[1];  //for the first element, create a new array nested in it
foos[0][0] = new Foo[1]; //create a third level new array nested in it
AaronLS
Hi aaronls, I want to have a three dimensional array. I have tried, but still has compile error. Please check my code version 2 in my original post for my new code and compile error. Any ideas or comments?
George2
@aaronls, I have followed your comments to add version 3 of my code. Could you help to review whether my code is correct to implement my goal please? Thanks!
George2
version 3 looks correct, but note it can hold only a single value.
AaronLS
@aaronls, thanks!
George2
+2  A: 

You are declaring a double-nested array (array of array of array) and assigning a three-dimensional array. Those two are definitely different. You can change your declaration to

Foo[,,] foos = new Foo[1,1,1]

if you want a truly three-dimensional array. Jagged arrays (the [][][] kind) are not that needed in C# as in, say, Java.

Joey
@Johannes, let us make things easier, say change dimension from 3 to 2, then what is the differneces between nested array and 2 dimensional array? :-)
George2
Jon Skeet has a nice answer on that. Basically, an n-dimensional array is exactly that: a single array with n dimensions. Whereas the [][] variant is an array of arrays, i.e. every element of the array is an array itself, which is in languages that support the first kind very rarely necessary.
Joey
@Johannes, thanks! I learned that it seems that multi-dimensional array is slower than jagged array because of GetLength boundary checking? I am confused that I think jagged array also needs such boundary checking, why jagged array is faster?
George2
Hmm, interesting. Didn't know that. In any case: If yout think that performance is a problem, profile it. Just try it out and find out where the bottlenecks are. You can always wrap it in an unchecked block if bounds checking is a problem.
Joey
@Johannes, I do not think it is a problem. I am just technically interested why. Any ideas?
George2
No, at the moment not really. If you benchmarked it yourself and came to the same conclusions you might ask one of the C# compiler guys about it. Eric Lippert seems to be pretty responsive, as far as I know.
Joey
@Johannes, I am just interested in some internal implementations for this case, more than a real performance issue.
George2
If looking at the IL doesn't help then just ask someone who knows. As I said, MS employees tend to answer mails :). I certainly won't get to some experimentation until later today.
Joey
+2  A: 

The simplest answer is to use

Foo[,,] foos = new Foo[2, 3, 4];

Which gives you a 3-dimensional array as a contiguous block of memory of 2*3*4=24 Foo's.

The alternative looks like :

Foo[][][] foos = new Foo[2][][];

for (int a = 0; a < foos.Length; a++)
{
  foos[a] = new Foo[3][];
  for (int b = 0; b < foos[a].Length; b++)
  {
     foos[a][b] = new Foo [4];

     for (int c = 0; c < foos[a][b].Length; c++)
        foos[a][b][c] = new Foo();
  }
}

Although this jagged (= array of array) approach is a bit more work, using it is actually faster. This is caused by a shortcoming of the compiler that will always do a range check when accessing an element in the Foo[,,] case, while it is able to at least optimize for-loops that use the Length property in the Foo[][][] scenario.

Also see this question

Henk Holterman
"a bit more work using it is actually faster" -- why faster?
George2
@George2: I explained it a little and added a link
Henk Holterman
@Henk, I have followed your comments to add version 3 of my code. Could you help to review whether my code is correct to implement my goal please? Thanks!
George2
@Henk, I read the question you recommended for 2 hours. Seems multi-dimensional array is slow because of GetLength boundary checking? I am confused that I think jagged array also needs such boundary checking, why jagged array is faster?
George2
@George2, The (JIT?) compiler does a special trick when it recognizes a for loop with i < a.Length condition. It should be able to do that for i < GetLenght(1) too, but it doesn't. Otherwise Foo[][][] would have been faster.
Henk Holterman
@Henk, which JITed instruction do you think is bad which causes multi-dimensional array slower than jagged array? Could you quote to make it more clear please?
George2
+1  A: 

These two different array declarations create very different things.

Let's look at simpler case:

Foo[,] twoDimensionArray = new Foo[5,5];

This array has two dimensions - you can think of it as a table. You need both axis in order to return anything:

Foo item = twoDimensionArray[2,3]

The indexes always have the same lengths - in this case 0-4.

A jagged array is actually an array of arrays:

Foo[][] jaggedArray = new Foo[5][];

jaggedArray[0] = new Foo[2];
jaggedArray[1] = new Foo[4];
...

If you only use one axis index it will return an array:

Foo[] oneRow = jaggedArray[3];

If you use both you make your selection from the sub-array:

Foo item = jaggedArray[3][2];

//would be the same as:
Foo item = oneRow[2];

Each of these sub-arrays can have a different length, or even not be populated.

Keith
@Keith, what do you mean "even not be populated"? Say in some other words?
George2
I have followed your comments to add version 3 of my code. Could you help to review whether my code is correct to implement my goal please? Thanks!
George2
By "not be populated" I mean that the sub-arrays can be null - they are when you initialise it.
Keith
+6  A: 

Regarding version 2 of your code - unfortunately you can't specify jagged arrays in that way. Instead, you need to do:

Foo[][][] foos = new Foo[1][][];
foos[0] = new Foo[1][];
foos[0][0] = new Foo[1];

You have to populate each array separately, basically. Foo[][][] means "an array of arrays of arrays of Foo." An initialization statement like this is only capable of initializing one array at a time. With the rectangular array, you still end up with just a single (multi-dimensional) array, which is why new Foo[1,1,1] is valid.

If this is for real code by the way, I'd urge you to at least consider other design decisions. Arrays of arrays can be useful, but you can easily run into problems like this. Arrays of arrays of arrays are even nastier. There may be more readable ways of expressing what you're interested in.

Jon Skeet
@Jon, I have followed your comments to add version 3 of my code. Could you help to review whether my code is correct to implement my goal please? Thanks!
George2
@Jon, your advice is very helpful. Actually the array definition is from xsd tool automatically generated C# file. :-(
George2
@George2: Have commented on the question. It's a shame it's autogenerated code. You might want to put a more readable facade around it.
Jon Skeet
Thanks Jon, I will take care next time. Developers are lazy sometimes. :-)
George2
@Jon, I learned that it seems that multi-dimensional array is slower than jagged array because of GetLength boundary checking? I am confused that I think jagged array also needs such boundary checking, why jagged array is faster?
George2
Multi-dimensional arrays are slower in some respects. The CLR actually has two types - arrays and vectors. Vectors are always single dimensional, with a lower bound of 0. This includes jagged arrays. Any multi-dimensional array is more general, and can have non-zero lower bounds. (Continued)
Jon Skeet
This means that bounds checking (and indexing in general) is slower with multi-dimensional arrays. However, I would rarely use that as the reason to choose one form over the other - most apps won't notice the difference. Pick the one which gives you the cleanest design.
Jon Skeet
@Jon, "This means that bounds checking (and indexing in general) is slower with multi-dimensional arrays" -- in other words, it is because each time we access an element in multi-dimensional array, we need to check every bound including non-zero based bound scenario, but to access (continued)
George2
vector/jagged array, we only need to check one bound each time and bound is always zero based, so simpler than multi-dimensional array. Which makes the conclusion that multi-dimensional array is slower? My understanding correct?
George2
@Jon, "Pick the one which gives you the cleanest design" -- agree.
George2
@George2: Yes, checking one bound is faster than checking two. Likewise doing "addr = base + index * size" is quicker than "add = base + (index - lowerBound) * size". I suspect there are more complexities too, but basically the vector CLR type is more heavily optimised than array.
Jon Skeet
A: 

If it means anything, for just the C# declaration:

int[,,] ary = new int[,,]
{
      { { 111, 112 }, { 121, 122 }, { 131, 132 } } 
    , { { 211, 212 }, { 221, 222 }, { 231, 232 } } 
    , { { 311, 312 }, { 321, 322 }, { 331, 332 } } 
    , { { 411, 412 }, { 421, 422 }, { 431, 432 } } 
};
A: 

How can I this unlimitted and enter the value on textbox.

umut