Let's say I have a class like this:
public class Fraction { int numerator; int denominator; public Fraction(int n, int d) { // set the member variables } // And then a bunch of other methods }
I want to initialize an array of them in a nice way, and this post is a big list of approaches that are error prone or syntactically cumbersome.
Of course an array constructor would be nice, but there's no such thing:
public Fraction[](params int[] numbers)
So I'm forced to use a method like
public static Fraction[] CreateArray(params int[] numbers) { // Make an array and pull pairs of numbers for constructor calls }
which is relatively clunky, but I don't see a way around it.
Both forms are error prone because a user could mistakenly pass an odd number of parameters, maybe because s/he skipped a value, which would leave the function scratching its head wondering what the user actually wanted. It could throw an exception, but then the user would need to try/catch. I'd rather not impose that on the user if possible. So let's enforce pairs.
public static Fraction[] CreateArray(params int[2][] pairs)
But you can't call this CreateArray in a nice way, like
Fraction.CreateArray({0,1}, {1,2}, {1,3}, {1,7}, {1,42});
You can't even do
public static Fraction[] CreateArray(int[2][] pairs) // Then later... int[2][] = {{0,1}, {1,2}, {1,3}, {1,7}, {1,42}}; Fraction.CreateArray(numDenArray);
Note that this would work just fine in C++ (I'm pretty sure).
You're forced to do one of the following instead, which is abhorrent. The syntax is terrible and it seems really awkward to use a jagged array when all the elements have the same length.
int[2][] fracArray = {new int[2]{0,1}, /*etc*/); Fraction.CreateArray(fracArray); // OR Fraction.CreateArray(new int[2]{0,1}, /*etc*/);
Similarly, Python-style tuples are illegal and the C# version is icky:
Fraction.CreateArray(new Tuple<int,int>(0,1), /*etc*/);
The use of a pure 2D array might take the following form, but it's illegal, and I'm sure there's no legal way to express it:
public static Fraction[] CreateArray(int[2,] twoByXArray) // Then later... Fraction[] fracArray = Fraction.CreateArray(new int[2,4]{{0,1}, {1,2}, {1,3}, {1,6}});
This doesn't enforce pairs:
public static Fraction[] CreateArray(int[,] twoByXArray)
OK, how about
public static Fraction[] CreateArray(int[] numerators, int[] denominators)
But then the two arrays might have different lengths. C++ allows
public static Fraction[] CreateArray<int N>(int[N] numerators, int[N] denominators)
but, well, this isn't C++, is it?
This sort of thing is illegal:
public static implicit operator Fraction[](params int[2][] pairs)
and unworkable anyway, again because of the abhorrent syntax:
Fraction[] fracArray = new Fraction[](new int[2]{0,1}, /*etc*/ );
This might be nice:
public static implicit operator Fraction(string s) { // Parse the string into numerator and denominator with // delimiter '/' }
Then you can do
string[] fracStrings = new string[] {"0/1", /*etc*/}; Fraction[] fracArray = new Fraction[fracStrings.Length]; int index = 0; foreach (string fracString in fracStrings) { fracArray[index] = fracStrings[index]; }
I don't like this approach for five reasons. One, the implicit cast unavoidably instantiates a new object, but we already have a perfectly good one, namely the one we're trying to initialize. Two, it can be confusing to read. Three, it forces you to do explicitly what I wanted to encapsulate in the first place. Four, it leaves room for bad formatting. Five, it involves one-time parsing of string literals, which is more like a practical joke than good programming style.
The following also requires wasteful instantiation:
var fracArray = Array.ConvertAll(numDenArray, item => (Fraction)item);
The following use of a property has the same problem unless you use those terrible jagged arrays:
public int[2] pair { set { numerator = value[0]; denominator = value[1]; } } // Then later... var fracStrings = new int[2,4] {{0,1}, /*etc*/}; var fracArray = new Fraction[fracStrings.Length]; int index = 0; foreach (int[2,] fracString in fracStrings) { fracArray[index].pair = fracStrings[index]; }
This variation doesn't enforce pairs:
foreach (int[,] fracString in fracStrings) { fracArray[index].pair = fracStrings[index]; }
Again, this approach is big anyway.
These are all of the ideas I know how to derive. Is there a good solution?
Array Initialization Using a Loop The following syntax uses a “for loop” to initialize the array elements. This is the most common way to initialize an array in C. // declare an array. int my_array[5];
Initializing an array In order to store values in the array, we must initialize it first, the syntax of which is as follows: datatype [ ] arrayName = new datatype [size];
Initializer List: To initialize an array in C with the same value, the naive way is to provide an initializer list. We use this with small arrays. int num[5] = {1, 1, 1, 1, 1}; This will initialize the num array with value 1 at all index.
An array may be partially initialized, by providing fewer data items than the size of the array. The remaining array elements will be automatically initialized to zero.
I can't think of an elegant, and at the same time memory efficient solution for array.
But there is an elegant solution for list (and similar) utilizing the C# 6 collection initializer feature:
public static class Extensions { public static void Add(this ICollection<Fraction> target, int numerator, int denominator) { target.Add(new Fraction(numerator, denominator)); } }
With that extension method in place, you can easily initialize a Fraction
list for instance:
var list = new List<Fraction> { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 7 }, { 1, 42 } };
And of course, although not memory efficient, you can use it to initialize Fraction
array either:
var array = new List<Fraction> { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 7 }, { 1, 42 } }.ToArray();
or even making it more concise by declaring a list derived class with implicit array conversion operator:
public class FractionList : List<Fraction> { public static implicit operator Fraction[](FractionList x) => x?.ToArray(); }
and then use
Fraction[] array = new FractionList { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 7 }, { 1, 42 } };
You could create a fraction array builder with a fluent interface. It would lead to something like
public class FractionArrayBuilder { private readonly List<Fraction> _fractions = new List<Fraction>(); public FractionArrayBuilder Add(int n, int d) { _fractions.Add(new Fraction(n, d)); return this; } public Fraction[] Build() { return _fractions.ToArray(); } }
which can be called using
var fractionArray = new FractionArrayBuilder() .Add(1,2) .Add(3,4) .Add(3,1) .Build();
which is an easy to understand statement.
I have made a fiddle to demonstrate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With