From: http://msdn.microsoft.com/en-us/library/2s05feca.aspx
Notice that you cannot omit the new operator from the elements initialization because there is no default initialization for the elements:
int[][] jaggedArray3 =
{
new int[] {1,3,5,7,9},
new int[] {0,2,4,6},
new int[] {11,22}
};
What does it mean?
Why is it ok to omit new in:
int[] arrSimp = { 1, 2, 3 };
int[,] arrMult = { { 1, 1 }, { 2, 2 }, { 3, 3 } };
but not possible in:
int[][,] arrJagg = {new int[,] { { 1, 1} }, new int[,] { { 2, 2 } }, new int[,] { { 3, 3 } } };
First off, what a coincidence, an aspect of your question is the subject of my blog today:
http://ericlippert.com/2013/01/24/five-dollar-words-for-programmers-elision/
You've discovered a small "wart" in the way C# classifies expressions. As it turns out, the array initializer syntax {1, 2, 3} is not an expression. Rather, it is a syntactic unit that can only be used as part of another expression:
new[] { 1, 2, 3 }
new int[] { 1, 2, 3 }
new int[3] { 1, 2, 3 }
new int[,] { { 1, 2, 3 } }
... and so on
or as part of a collection initializer:
new List<int> { 1, 2, 3 }
or in a variable declaration:
int[] x = { 1, 2, 3 };
It is not legal to use the array initializer syntax in any other context in which an expression is expected. For example:
int[] x;
x = { 1, 2, 3 };
is not legal.
It's just an odd corner case of the C# language. There's no deeper meaning to the inconsistency you've discovered.
In essence the answer is "because they (meaning the language designers) choose not to.To quote from Eric Lippert:
The same reason why every unimplemented feature is not implemented:
features are unimplemented by default. In order to become implemented
a feature must be (1) thought of, (2) designed, (3) specified, (4)
implemented, (5) tested, (6) documented and (7) shipped.
More technically there is a good reason to it and that's the definition of jagged arrays compared to 1-dimension and multi-dimension arrays.
A one or more dimension arrays can be expressed in plain English as a X dimension array of T where a jagged array has to be expressed as an Array of arrays of T. In the second case, there is a loose coupling between the inner array and the outer arary. That is, you can assign a new array to a position within the outer array whereas a x dimension array is fixed.
Now that we know that Jagged arrays are very different from multi-dimensional arrays in their implementation, we can also assume why there is a different level of integrated support for the 2. It's certainly not impossible to add support, just a question of demand and time.
(as a teaser, why only add support for jagged arrays? how about your own custom types?)
Related
I can not understand the difference between the declaration with array initialization in the first case and the second
int[] array = new int[3] { 1, 2, 3 };
int[] secondArray = { 1, 2, 3 };
They seem to do the same thing, maybe they work differently?
The is no difference in the result between the two show lines shown:
int[] array = new int[3] { 1, 2, 3 };
int[] secondArray = { 1, 2, 3 };
However, there are practical differences between new int[n] {...} syntax and {...}:
Implicit type is not available for the alternative array initialiser:
var a1 = new int[3] { 1, 2, 3 }; // OK
var a2 = { 1, 2, 3 }; // Error: Cannot initialize an implicitly-typed variable with an array initializer
// BTW. You can omit the size
var a3 = new int[] { 1, 2, 3 }; // OK
With the alternative syntax you cannot specify the size, it's always inferred.
var a1 = new int[100]; // Array with 100 elements (all 0)
int[] a2 = { }; // Array with no elements
There is no difference in the compiled code between the two lines.
The second one is just a shortcut. Both statements have the same result. The shorter variant just wasn't available in early versions of C#.
The first one uses 3 as a array size explictly, the 2nd one size is inferred.
This might be work if you dont want to initialize the values.
There is no difference between this two array initialization syntaxes in terms how they will be translated by the compiler into IL (you can play with it at sharplab.io) and it is the same as the following one:
int[] thirdArray = new int[] { 1, 2, 3 };
The only difference comes when you are using those with already declared variable, i.e. you can use 1st and 3rd to assign new value to existing array variable but not the second one:
int[] arr;
arr = new int[3] { 1, 2, 3 }; // works
// arr = { 1, 2, 3 }; // won't compile
arr = new int[] { 1, 2, 3 }; // works
What is the difference between these two:
string[,] array1;
and
string[][] array2;
Could someone please explain me about these two in terms of applications and functionality, memory management etc... how do you called them, which one is better to use? how to initialize them?
array1 is called a reference to a multidimensional array; array2 is a reference to a jagged array.
The first one is designed to store rectangular data which is not sparse and the number of elements in the dimensions are almost the same. You can initialize it like:
// Two-dimensional array.
int[,] array1= new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
In the latter case which is also called array of array the elements can be of different dimensions and sizes. Some times it is memory optimized to store sparse 2d data in the RAM. You can initialize it like:
int[][] array2= new int[][]
{
new int[] { 1, 3, 5, 7, 9 },
new int[] { 0, 2, 4, 6 },
new int[] { 11, 22 }
};
Absolutely the usage is depends on you requirements and purposes. You can review these 1, 2.
Consider the following method of shuffling, given an array of objects a
Take the first element from a and place it into b. Consider the index of this element inside b to be x.
Place the second element from a and place it in front of b[x], so that it is now in position b[x-1]
Place the third element from a and place it behind b[x], so that it is now in position b[x+1]
Place the fourth element from a and place it in front of b[x - 1], so that it is now in position b[x-2]
Place the firth element from a and place it behind b[x+1] so that it is now in position b[x+2]
Repeat this process until b has all of the elements from a in it in this new shuffled order.
I wrote some code which does this, shown below. It will continuously shuffle the array in the above process until the shuffled array matches the original array, and then return the number of shuffles.
public class BadShuffler
{
public BadShuffler(object[] _arrayToShuffle)
{
originalArray = _arrayToShuffle;
Arrays = new List<object[]>
{
originalArray
};
}
private object[] originalArray;
private int count;
public List<object[]> Arrays { get; set; }
public int Shuffle(object[] array = null)
{
if (array == null)
array = originalArray;
count++;
object[] newArray = new object[array.Length];
bool insertAtEnd = false;
int midpoint = newArray.Length / 2;
newArray[midpoint] = array[0];
int newArrayInteger = 1;
int originalArrayInteger = 1;
while (newArray.Any(x => x == null))
{
if (insertAtEnd)
{
newArray[midpoint + newArrayInteger] = array[originalArrayInteger];
newArrayInteger++;
}
else
{
newArray[midpoint - newArrayInteger] = array[originalArrayInteger];
}
originalArrayInteger++;
insertAtEnd = !insertAtEnd;
}
Arrays.Add(newArray);
return (newArray.All(x => x == originalArray[Array.IndexOf(newArray, x)])) ? count : Shuffle(newArray);
}
}
While not being the prettiest thing in the world, it does the job. Example shown below:
Shuffled 6 times.
1, 2, 3, 4, 5, 6
6, 4, 2, 1, 3, 5
5, 1, 4, 6, 2, 3
3, 6, 1, 5, 4, 2
2, 5, 6, 3, 1, 4
4, 3, 5, 2, 6, 1
1, 2, 3, 4, 5, 6
However, if I give it an array of [1, 2, 3, 3, 4, 5, 6] it ends up throwing a StackOverflowException. When debugging, however, I have found that it does actually get to a point where the new shuffled array matches the original array, as shown below.
This then goes on to call Shuffle(newArray) again, even though all values in the array match each other.
What is causing this? Why does the Linq query newArray.All(x => x == originalArray[Array.IndexOf(newArray, x)]) return false?
Here is a DotNetFiddle link, which includes the code I used to print out the result(s)
You are comparing objects. objects are compared using referential equality with ==, not value equality. Your example uses numbers, but those numbers are boxed to an object implicitly due to the way your code is laid out.
To avoid this, you should use the .Equals() function (when comparing Objects).
newArray.All(x => x.Equals(originalArray[Array.IndexOf(newArray, x)]))
You should also use generics in your class instead of littering object[] everywhere to ensure type safety - unless one of your aims with this shuffler is to allow the shuffler to shuffle arrays of mixed types (which seems doubtful since it would be hard to extract any useful information out of that).
Note that this behaviour is exhibited whenever you are comparing reference types; one way to only allow value types to be passed to your structure (i.e, only primitive values that can be compared by value equality rather than referential equality) is to use the struct generic constraint. As an example:
class BadShuffler<T> where T : struct
{
public bool Shuffle(T[] array)
{
...
return newArray.All(x => {
var other = originalArray[Array.IndexOf(originalArray, x)];
return x == other;
});
}
}
This would work as you expect.
SequenceEqual as mentioned in the comments is also a good idea, as your .All() call will say that [1, 2, 3] is equal to [1, 2, 3, 4], but [1, 2, 3, 4] will not be equal to [1, 2, 3] - both of these scenarios are incorrect and more importantly not commutative[1], which equality operations should be.
Just make sure you implement your own EqualityComparer if you go beyond using object[].
That said, I think you want to use a combination of both approaches and use SequenceEqual with my approach, unless you need to shuffle objects (I.e, a Deck of Cards) rather than numbers?
As a side note, I would generally recommend returning a new, shuffled T[] rather than modifying the original one in-place.
[1]: Commutative means that an operation done one way can be done in reverse and you get the same result. Addition, for example, is commutative: you can sum 1, 2 and 3 together in any order but the outcome will always be 6.
For C# in VS2005, can you do something like this:
if number in [1,2..10,12] { ... }
which would check if number is contained in the set defined in the square brackets?
.NET 2.0 (which is what VS 2005 targets) doesn't have the notion of a Set.
.NET 3.5 introduced HashSet<T>, and .NET 4 introduced SortedSet<T>.
There isn't a literal form for them though - although collection initializers provide something slightly similar:
new HashSet<int> { 1, 2, 4, 12 }
Of course, you could just use an array:
int[] values = { 1, 2, 5, 12 };
but the range part of your sample - 2..10 - doesn't exist in any version of C#.
Unfortunately not.
However, you can use the Contains() method of a List<int>:
List<int> numbers = ...
if (numbers.Contains(2)) { ... }
if numbers is an array, you can either initialize a new List<int> with the array values:
int[] numbers = { 1, 2, 3, 4 };
List<int> newList = new List<int>(numbers);
if (newList.Contains(2)) { ... }
or use Array.Exists():
Array.Exists(numbers, delegate(int i) { return i == 2; });
You can "kind of" do what you want using the Enumerable.Range method:
if (Enumerable.Range(2, 8).Concat(new [] { 1, 12 }).Contains(number)) {
....
}
Of course, that's not nearly as readable as what you find in a basic functional language...
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
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.
Make up your mind :)
You either want:
Foo[,,] foos = new Foo[1, 1, 1];
or:
Foo[][][] foos = new Foo[1][1][1];
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.
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
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.
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
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 } }
};
Array Initialization
int[, ,] array3D = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } },
{ { 7, 8, 9 }, { 10, 11, 12 } } }
source: Multidimensional Arrays (C# Programming Guide)