Dynamic Initialize in c# - c#

I've a class
class sampleClass
{
...........
...........
public sampleClass()
{.........}
}
and in another class i created an array like
sampleClass[] X=new sampleClass[]{new sampleClass(),new sampleClass()}
here i gave 2 instance of the constructor. i need this dynamically..
that is the size of the array should be dynamically changed

It sounds like you want something like:
int size = // whatever
SampleClass[] array = new SampleClass[size];
for (int i = 0; i < size; i++)
{
array[i] = new SampleClass();
}
EDIT: If you really want to avoid a for loop, you could do something like:
SampleClass[] array = Enumerable.Range(0, size)
.Select(x => new SampleClass())
.ToArray();
... but I don't think that's actually better than using a loop.

This is just a syntactic sugar, you can gain the same using your own code:
sampleClass[] X = new sampleClass[num];
for(int i = 0; i < num; i++)
{
X[i] = new sampleClass();
}

You can initialize the array using a loop:
sampleClass[] X = new sampleClass[123];
for (int i = 0; i < X.Length; ++i)
X[i] = new sampleClass();
If your class was a value type the array is initialized when it is allocated:
struct sampleStruct { ... }
sampleStruct[] X = new sampleStruct[123];
// No need to initialize every array cell.
However, using a struct instead of a class is not something you should do simply to avoid a loop. You can read more about value types on MSDN.

Related

Why "foo = new double[int x, int y]" is legal but not "foo = new double[int x][int y]"?

I know there are differences between jagged and multidimensional arrays. I know it is often likeable to use a "List<>" instead of arrays of arrays.
Could someone just explain me why, in the following code, the first is allowed but the second is an error? I just want to better understand C#...
Legal:
public class Banana
{
double[,] _banana;
public Banana(int h, int w)
{
_banana= new double[h,w];
}
}
Illegal (Error: a constant value is expected instead of h and w):
public class Banana
{
double[][] _banana;
public Banana(int h, int w)
{
_banana= new double[h][w]{};
}
}
TL;DR;
Why is it possible to initialize the dimensions of a multi array with variables but not a jagged array's?
An int[4,5] is single object which holds twenty integers. An int[4][] is an object which holds four references to integer arrays. Having int[][] foo = new int[4][5]; be equivalent to:
int[][] foo = new int[4][];
for (int temp = 0; temp < 4; temp++)
foo[i] = new int[5];
would make about as much sense as having StringBuilder bar[] = new StringBuilder[4](); be equivalent to:
StringBuilder bar = new StringBuilder[4];
for (int temp = 0; temp < 4; temp++)
bar[i] = new StringBuilder();
Such a feature might be helpful in many cases, and there wouldn't be anything particularly wrong with it conceptually, but the code required to explicitly initialize array elements isn't particularly onerous, and writing such code explicitly helps make clear that the array-of-references and the things to which those references refers are all separate entities.
With a jagged array you have to initialize each "leg" separately - there's no syntax to initialize the size of each leg in one pass:
public Banana(int h, int w)
{
_banana = new double[h][];
for (int i = 0; i < h; i++)
{
_banana[i] = new double[w];
}
}
Why is there no syntax? Because the spec doesn't require it, and in a "typical" jagged array the legs have different lengths, otherwise a 2-D array may be more appropriate.
Each nested array in a jagged array can have a different length. If you had to initialize it using your syntax example, they would all be required to have the same length. It simply doesn't make sense. You'd have to use something like:
_banana = new double[h][];
for(var i = 0; i < h; i++)
{
_banana[h] = new double[w];
}

Custom iteration for multi-dimensional arrays?

Something like:
forelement (element G_Element, Grid)
{
Grid[G_Element.dim1, G_Element.dim2] =
new clsGridElement(G_Element.dim1, G_Element.dim2);
}
instead of
for (int X = 0; X < GridWidth; X++)
for (int Y = 0; Y < GridHeight; Y++)
Grid[X, Y] = new clsGridElement(X, Y);
If something doesn't innately exist, is that something that could be created?
Thanks,
Tim
You could do this - just make a custom type that exposes these, and use a regular foreach:
public class TwoDimensionalIterator
{
public TwoDimensionalIterator(int i, int j)
{
this.Dim1 = i; this.Dim2 = j;
}
public int Dim1 { get; private set; }
public int Dim2 { get; private set; }
}
Then make an extension method somewhere to return an enumerable of this:
public static IEnumerable<TwoDimensionalIterator> IterateTwoDim<T>(this T[,] array)
{
for (int i=0;i<array.GetLength(0);++i)
for (int j=0;i<array.GetLength(1);++j)
yield return new TwoDimensionalIterator(i,j);
}
With this, you could then do:
foreach(var index in Grid.IterateTwoDim())
{
Grid[index.Dim1, index.Dim2] = new clsGridElement(index.Dim1, index.Dim2);
}
Not sure exactly what you are trying to do here, or why, or what you expect to get from it, but if you implement your own iterator than implements the IEnumerator interface then you could create something that would hit every cell in your 2D (or more) collection.
Of course, you won't actually gain anything performance-wise from doing this versus just using nested loops, but I guess it'd be syntactic sugar.
Such creation of indexes can be obtained by using "Cartesian product" of all indexes. Here is sample based on Is there a good LINQ way to do a cartesian product? (courtesy of the Eric Lippert):
var allIndexes = from dim1 in Enumerable.Range(0, Grid.GetLength(0))
from dim2 in Enumerable.Range(0, Grid.GetLength(1))
select new {dim1, dim2};
foreach (var G_Element in allIndexes)
{
Grid[G_Element.dim1, G_Element.dim2] =
new clsGridElement(G_Element.dim1, G_Element.dim2);
}

Changing one element of an array changes others

I have the following piece of code:
Chromosome[] pop = new Chromosome[popSize];
int[] initialGenes = new int[i];
for (int m = 0; m < i; m++)
initialGenes[m] = -1;
for (int j = 0; j < popSize; j++)
{
pop[j] = new Chromosome(graph, initialGenes);
}
Chromosome is my class and has a property
public int[] Genes { get; set; }
As you can see I initialize an array of Chromosome objects. The problem is when I try to change the value of pop[i].Genes[k] (e.g. pop[1].Genes[2] = 123) all Genes[k] of pop are changed (i.e.
pop[0].Genes[2] == 123
pop[2].Genes[2] == 123
etc.)
Could anyone explain what the problem is?
Thanks.
Change your constructor of Chromosome to make a copy of the array that is passed in.
I assume, your constructor looks like this:
public Chromosome(int[] initialGenes)
{
Genes = initialGenes;
}
But it should look like this:
public Chromosome(int[] initialGenes)
{
Genes = new int[initialGenes.Length];
Array.Copy(initialGenes, Genes, Genes.Length);
}
This happens because you pass same object to all Chromosome clases. You should create new copy of initialGenes for each Chromosome class

Initializing jagged arrays

I want to create array 10 * 10 * 10 in C# like int[][][] (not int[,,]).
I can write code:
int[][][] count = new int[10][][];
for (int i = 0; i < 10; i++)
{
count[i] = new int[10][];
for (int j = 0; j < 10; j++)
count[i][j] = new int[10];
}
but I am looking for a more beautiful way for it. May be something like that:
int[][][] count = new int[10][10][10];
int[][][] my3DArray = CreateJaggedArray<int[][][]>(1, 2, 3);
using
static T CreateJaggedArray<T>(params int[] lengths)
{
return (T)InitializeJaggedArray(typeof(T).GetElementType(), 0, lengths);
}
static object InitializeJaggedArray(Type type, int index, int[] lengths)
{
Array array = Array.CreateInstance(type, lengths[index]);
Type elementType = type.GetElementType();
if (elementType != null)
{
for (int i = 0; i < lengths[index]; i++)
{
array.SetValue(
InitializeJaggedArray(elementType, index + 1, lengths), i);
}
}
return array;
}
You could try this:
int[][][] data =
{
new[]
{
new[] {1,2,3}
},
new[]
{
new[] {1,2,3}
}
};
Or with no explicit values:
int[][][] data =
{
new[]
{
Enumerable.Range(1, 100).ToArray()
},
new[]
{
Enumerable.Range(2, 100).ToArray()
}
};
There is no built in way to create an array and create all elements in it, so it's not going to be even close to how simple you would want it to be. It's going to be as much work as it really is.
You can make a method for creating an array and all objects in it:
public static T[] CreateArray<T>(int cnt, Func<T> itemCreator) {
T[] result = new T[cnt];
for (int i = 0; i < result.Length; i++) {
result[i] = itemCreator();
}
return result;
}
Then you can use that to create a three level jagged array:
int[][][] count = CreateArray<int[][]>(10, () => CreateArray<int[]>(10, () => new int[10]));
With a little help from Linq
int[][][] count = new int[10].Select(x => new int[10].Select(x => new int[10]).ToArray()).ToArray();
It sure isn't pretty and probably not fast but it's a one-liner.
There is no 'more elegant' way than writing the 2 for-loops. That is why they are called 'jagged', the sizes of each sub-array can vary.
But that leaves the question: why not use the [,,] version?
int[][][] count = Array.ConvertAll(new bool[10], x =>
Array.ConvertAll(new bool[10], y => new int[10]));
A three dimensional array sounds like a good case for creating your own Class. Being object oriented can be beautiful.
You could use a dataset with identical datatables. That could behave like a 3D object (xyz = row, column, table)... But you're going to end up with something big no matter what you do; you still have to account for 1000 items.
Why don't you try this?
int[,,] count = new int[10, 10, 10]; // Multi-dimentional array.
Any problem you see with this kind of representation??

How to initialize an array of arrays (or jagged array) using CodeDom?

I'm trying to use CodeDom to generate C# (.Net 2.0) code that would do the following:
int[][] myArray = new int[someSize][];
In CodeDom, initializing an array requires a CodeArrayCreateExpression. The MSDN says:
If a language allows arrays of arrays, it is possible to create them by nesting a CodeArrayCreateExpression within a CodeArrayCreateExpression.
The way I understand it, the only possibility is to write something like this:
// Declaration and initialization of myArray
CodeVariableDeclarationStatement variable =
new CodeVariableDeclarationStatement("System.Int32[][]", "myArray",
new CodeArrayCreateExpression("System.Int32[][]",
new CodeExpression[] { new CodeArrayCreateExpression("System.Int32[]", 0) }));
But this generates this:
int[][] myArray = new int[][] { new int[0] };
That's not perfect but I could do with it if I knew the size of myArray at generation time, which I don't.
I could write a function that does the initialization and call it in CodeDom but it would be nicer if I could do it in pure CodeDom. Did I miss something ?
[EDIT] Background information
The idea is to automatically generate an adapter between two object representations. I have a meta-description (some kind of IDL) saying: "I have a container object which has a field of type int[][]" and two representations of this container:
// Internal representation
public class InternalContainer {
int[][] myArray;
}
// Network representation
public class NetworkContainer {
int[][] myArray;
}
Thus the question of generating code that can adapt to any size of array.
You have the following workaround to create a jagged array with a dynamic length:
Create the dom equivalent of
ELEMENTTYPE[] array = (ELEMENTTYPE[])Array.CreateInstance(typeof(ELEMENTTYPE), length);
ELEMENTTYPE can be any type, be it an array or not.
Here's my solution, using a CodeSnippetExpression
public static DOM.CodeExpression NewArray (this Type type, int dim, int size) {
string dims = String.Concat(Enumerable.Repeat("[]", dim - 1).ToArray());
return new DOM.CodeSnippetExpression(string.Format("new {0}[{1}]{2}", type.FullName, size, dims));
}
CodeArrayCreateExpression CodeArrayCreateExpression(Array array)
{
CodeArrayCreateExpression arrayCreateExpression = new CodeArrayCreateExpression(array.GetType(), array.GetLength(0));
if (array.GetType().GetElementType().IsArray)
{
CodeArrayCreateExpression[] values = new CodeArrayCreateExpression[array.GetLength(0)];
for (int j = 0; j < array.GetLength(0); j++)
{
values[j] = this.CodeArrayCreateExpression((Array)array.GetValue(j));
}
arrayCreateExpression.Initializers.AddRange(values);
}
else if(array.GetType().GetElementType().IsPrimitive)
{
CodeCastExpression[] values = new CodeCastExpression[array.GetLength(0)];
for (int j = 0; j < values.Length; j++)
{
values[j] = new CodeCastExpression();
values[j].Expression = new CodePrimitiveExpression(array.GetValue(j));
values[j].TargetType = new CodeTypeReference(array.GetType().GetElementType());
}
arrayCreateExpression.Initializers.AddRange(values);
}
return arrayCreateExpression;
}

Categories

Resources