How to elegantly populate a heterogeneous array in c# - c#

I have 3 different classes (1 parent and 2 children), and I have created a heterogeneous array:
Parent[] parentArray = new Parent[9];
I would like to populate this array with 3 Parent objects, 3 child1 objects, and 3 child2 objects, in that order.
I would like to know if there is a more elegant way to do it than just doing this:
parentArray[0] = new Parent();
parentArray[1] = new Parent();
parentArray[2] = new Parent();
parentArray[3] = new Child1();
parentArray[4] = new Child1();
....
parentArray[9] = new Child2();
Thanks!

Like this?
var parentArray = new Parent[]
{
new Parent(),
new Parent(),
new Parent(),
new Child1(),
...
};

Personal i just think you should use the object initializer. However for sheer boredom you can use Linq and a generic factory method.
// Given
public static IEnumerable<T> Factory<T>(int count) where T : Parent, new()
=> Enumerable.Range(0, count).Select(x => new T());
...
// Usage
var array = Factory<Parent>(3)
.Union(Factory<Child1>(3))
.Union(Factory<Child2>(3))
.ToArray();

In this situation, you want to perform a certain number of actions repeatedly. Loops are commonly used to do this. Because you're initializing an array, for loops are a good fit, as they expose an integer that can be used to index the array. In your scenario, you can use three such loops.
Parent[] parentArray = new Parent[9];
for (int i = 0; i < 3; i++)
{
parentArray[i] = new Parent();
}
for (int i = 3; i < 6; i++)
{
parentArray[i] = new Child1();
}
for (int i = 6; i < 9; i++)
{
parentArray[i] = new Child2();
}

Related

how to create a loop that creates lists

I want to create a loop that makes lists the name of the lists that need to come from another list.
I tried doing it like that.
for (int i = 0; i < Names.Count; i++)
{
List<string> Name[i] = new List<string>();
}
Just pass the source collection in the list constructor, like this
var newList = new List<string>(Names);
If you want more control, you can still do your loop, but declare the destination list first:
var newList = new List<string>();
for (int i = 0; i < Names.Count; i++)
{
newList.Add(Names[i]);
}
And finally, if you need a list of lists, where each list is named, you'd use a different data structure, for example a Dictionary<string, List<string>> instead:
var listOfLists = new Dictionary<string, List<string>>();
for (int i = 0; i < Names.Count; i++)
{
listOfLists.Add(
Names[i], // <--- the name of the list is the key
new() // <--- the named list (initially empty)
);
}
Which, in modern C#, can be shortened further to become
var listOfLists = Names.ToDictionary(name => name, _ => new List<string>());

Making var 's in a for-loop

It is hard to explain but I will show an example of what I want in my code:
At the moment I do it this way:
var something1 = new (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet);
var something2 = new (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet);
var something3 = new (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet);
something1.Name = "sheet1";
something2.Name = "sheet2";
something3.Name = "sheet3";
I want to do the making of those var's in a for-loop
This is what I thought it should be:
for (int i=1;i<4;i++)
{
var ("something" +i) = new Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet); // this (of course) doenst work
}
Any ideas on how to do this?
I tried this, but it didn't work:
var something = new (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1 , XlSheetType.xlWorksheet)[4];
you can use a dictionary
var somethigs = new Dictionary<int, xxx.ApplicationClass>();
for (var i = 1; i < 4; i++)
{
somethigs[i] = new xxx.ApplicationClass();
}
//access them like this
somethigs[1].Name = "sheet1";
somethigs[2].Name = "sheet2";
or use an array like this
var somethigs = new xxx.ApplicationClass[4];
for (var i = 0; i < 4; i++)
{
somethigs[i] = new xxx.ApplicationClass();
}
somethigs[0].Name = "sheet1";
somethigs[1].Name = "sheet2";
keep in mind that arrays have zero based indexes.
If you know for sure, the amount of instances you will need, creating an array or list of class instances will do what you are after.
If you want something more sophisticated, you could also create a dictionary in which you provide names to each of your class instances, this could provide you with an access by name sort of thing mechanism.
Dictionary<string, ApplicationClass> dictionary = new Dictionary<string, ApplicationClass>();
for(int i = 0; i < 4; i++) {
dictionary.Add("something" + i, new xxx.ApplicationClass());
}
var myApplicationClass = dictionary["something1"];
You should use an array. In your particular case,
var something = new xxx.ApplicationClass[4];
for (int i = 0; i < 3; i++)
{
something[i] = new (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet);
something[i].Name = "sheet" + (i + 1).ToString();
}
You should probably look for more information about what arrays an how they work. See for example https://msdn.microsoft.com/en-us/library/aa288453%28v=vs.71%29.aspx

Correct way to initialize object in array of objects so that i don't get null pointer references?

I am receiving a null pointer exception, and I narrowed it down to this small block of code. I think it is because when I set teamStats[iterator].median = Statistics.median that it can't because it isn't initialized yet. Though I don't know the proper way to initialize an array of objects or the memory ramifications that this code will cause.
Below is the majority of the code i am dealing with besides the class describing TeamStat, but I've used all of its members below and they are public double.
TeamStat[] teamStats = new TeamStat[DistCount+1];
int iterator = 0;
foreach (int i in TeamIDlist)
{
var p = userList.Where(x => x.TeamId.Equals(i)).Select(y => (double)y.BS).ToArray();
var statistics = new DescriptiveStatistics(p);
teamStats[iterator].median = Statistics.Median(p);
teamStats[iterator].largestElement = statistics.Maximum;
teamStats[iterator].smallestElement = statistics.Minimum;
teamStats[iterator].mean = statistics.Mean;
teamStats[iterator].variance = statistics.Variance;
teamStats[iterator].stdDev = statistics.StandardDeviation;
iterator++;
}
Update
Is this the correct way to do this:
TeamStat[] teamStats = new TeamStat[DistCount];
int iterator = 0;
foreach (int i in TeamIDlist)
{
//Added these two lines
TeamStat temp = new TeamStat();
teamStats[iterator] = temp;
var p = userList.Where(x => x.TeamId.Equals(i)).Select(y => (double)y.BS).ToArray();
var statistics = new DescriptiveStatistics(p);
teamStats[iterator].median = Statistics.Median(p);
teamStats[iterator].largestElement = statistics.Maximum;
teamStats[iterator].smallestElement = statistics.Minimum;
teamStats[iterator].mean = statistics.Mean;
teamStats[iterator].variance = statistics.Variance;
teamStats[iterator].stdDev = statistics.StandardDeviation;
iterator++;
}
Here
TeamStat[] teamStats = new TeamStat[DistCount+1];
you initialize the array. At this moment, the array contains DistCount + 1 null entries.
If you want the array to contain DistCount + 1 new TeamStat entries, you need to initialize them in a loop:
TeamStat[] teamStats = new TeamStat[DistCount+1];
for (var i = 0; i < DistCount + 1; i++)
teamStats[i] = new TeamStat();
Your code has 2 issues
1) Each object in Array needs to be initialized before accseing its properties
teamStats[iterator] = new TeamStat();
2) You need to make sure you initizliaed array with same/more capacity as you are trying to assign values to.(TeamIDlist < DistCount+1), otheriwse it will throw index out of range exception.

C#: Object Array with Constructor parameter

I have a class Measurement.
I have a constructor inside this class. as:
class Measurement
{
public Measurement(MainWindow mainWindow)
{
....
}
}
How can I create an Array of 8 Objects with the MainWindow Parameter?
Like somewhere in my code:
Measurement[] measurements= new Measurement[8](mainWin);
Do you want an array with a single reference 8 times, or 8 separate Measurement objects?
For the first:
var measurements = Enumerable.Repeat(new Measurement(mainWin), 8).ToArray();
For the second:
var measurements = Enumerable.Range(0, 8)
.Select(_ => new Measurement(mainWin))
.ToArray();
(Or just create an array without initializing the elements, then populate it with a loop, of course. It's a matter of personal preference.)
You can use LINQ:
var measurements = Enumerable.Range(0, 8).Select(i => new Measurement(mainWin)).ToArray();
A second way is to use the array initializer syntax:
var measurements = new[] {
new Measurements(mainWin), new Measurements(mainWin),
new Measurements(mainWin), new Measurements(mainWin),
new Measurements(mainWin), new Measurements(mainWin),
new Measurements(mainWin), new Measurements(mainWin)
};
There is this way (by using Enumerable.Repeat) :
var measurements = Enumerable.Repeat(new Measurement(mainWin), 8).ToArray();
Quote :
Generates a sequence that contains one repeated value.
Measurement[] measurements= new Measurement[8];
for(int i = 0; i < measurements.Length; i++)
{
measurements[i] = new Measurement(mainWin);
}

How can i create array of my class with default constructor?

For example
MYCLASS[] myclass = new MYCLASS[10];
Now myclass array is all null array but i want to have default constructed Array .I know that i can write loops for set default constructed but i am looking for more easy and simple way.
If you don't want to write out the loop you could use Enumerable.Range instead:
MyClass[] a = Enumerable.Range(0, 10)
.Select(x => new MyClass())
.ToArray();
Note: it is considerably slower than the method you mentioned using a loop, written here for clarity:
MyClass[] a = new MyClass[10];
for (int i = 0; i < a.Length; ++i)
{
a[i] = new MyClass();
}
var a = Enumerable.Repeat(new MYCLASS(), 10).ToArray();
There isn't an easier way. If you just don't like loops, you could use
MyClass[] array = new[] { new MyClass(), new MyClass(), new MyClass(), new MyClass() };
which would give you an array with 4 elements of type MyClass, constructed with the default constructor.
Otherwise, you just have the option to use a loop.
If you don't want to write that loop every time you want to construct your array, you could create a helper-method, for example as an extension method:
static class Extension
{
public static void ConstructArray<T>(this T[] objArray) where T : new()
{
for (int i = 0; i < objArray.Length; i++)
objArray[i] = new T();
}
}
And then use it like this:
MyClass[] array = new MyClass[10];
array.ConstructArray();
There isn't really a better way. You could do something like:
public static T[] CreateArray<T>(int len) where T : class, new() {
T[] arr = new T[len];
for(int i = 0 ; i <arr.Length ; i++) { arr[i] = new T(); }
return arr;
}
then at least you only need:
Foo[] data = CreateArray<Foo>(150);
This approach should at least avoid any reallocations, and can use the JIT array/length optimisation. The : class is to avoid use with value-types, as with value-types already initialize in this way; just new MyValueType[200] would be better.
You can use LINQ.
var a = (from x in Enumerable.Range(10) select new MyClass()).ToArray();
If we want to do all job in only one line code so this is best
MYCLASS[] myclass = (new MYCLASS[10]).Select(x => new MYCLASS()).ToArray();

Categories