My advise would be, if you are using complex structures, you should not use standard structures anymore, but create classes that represent the data that you model and the operations that you can perform on these objects.
Apparently your program has the notion of Matrix
(not sure if you use the same term in English mathematics)
A Matrix of M by N has M columns, and N rows.
I'm not sure if it is wise to put your abcarray
in a matrix of 3 by 1, or that you want to put that in a special class that you would call a Vector. Maybe a Vector is a derived class of matrix of N by 1? or 1 by N?
Anyway, apparently you can do an operation on two Vectors:
class Vector
{
public Matrix<T> CartesianProduct(Vector<T> v)
{
return CartesianProduct(this, v);
}
public static Matrix<T> CartesianProduct(Vector<T> x, Vector<T> y) {...}
Usage would be:
Vector<string> x = new Vector<string>(new string[] { "a", "b", "c" });
Vector<string> y = new Vector<string>(new string[] { "1", "2", "3" });
Matrix<string> m = x.CartesianProduct(y);
Well this looks neat enough to me, so let's continue on this path.
A Vector has a Dimension
. When creating a Vector object, you have to specify the Dimension
. During lifetime of the Vector you can't change its Dimension
.
A Vector has Coordinates
, numbered from 0 to Dimension-1
. You can get and set a specific Coordinate. For simplicity we use the index to access the Coordinates.
Operations that you can do on a Vector: Add / Subtract / Negate / Multiply / ... This is a bit out of scope of your question so I won't go in to this.
class Vector<T> : IReadonlyCollection<T>
{
private readonly T[] coordinates;
public Vector(int dimension)
{
// TODO: check dimension > 0;
this.coordinates = new T[dimension];
}
public Vector(IEnumerable<T> data)
{
// TODO: check data != null; check data contains at least one element
this.Coordinates = data.ToArray();
}
// TODO: other constructors? ICloneable?
// TODO: Add / Subtract / Multiply with a number?
public T this[int index]
{
get => this.coordinates[index];
set => this.coordinates[index] = value;
}
}
Implementation of IReadOnlyCollection is fairly straightforward:
public int Count => this.coordinates.Length;
public Enumerator<T> GetEnumerator()
{
return this.Coordinates.GetEnumerator();
}
IEnumerator Enumerable.GetEnumerator()
{
return this.GetEnumerator();
}
For initializations the following extension methods would be nice. If you are not familiar with extension methods, read extension methods demystified
public static Vector<T> AsVector<T>(IEnumerable<T> source)
{
return new Vector<T>(source.ToArray());
}
Usage:
var abcArray = new string[] { "a", "b", "c" };
var abcVector = abcArray.AsVector();
I design a Matrix as a non-changeable two dimensional array.
class Matrix<T>
{
private readonly T[,] elements;
public Matrix(int columnCount, int rowCount)
{
this.elements = new T[columnCount, rowCount];
}
public Matrix(T[,] elements)
{
this.elements = elements;
}
public int RolumnCount => this.elements.GetLength[0];
public int RowCount => this.elements.GetLength[1];
// etc, invent several other useful operations on matrices.
// addition, multiplication, linear transformation, ...
}
Of course, if you really want to interpret a Matrix as a two dimensional array:
public T[,] Elements => this.elements
Finally the cartesian product of two vectors, returning a Matrix. The problem is, that we need a function to "combine" one x-coordinate with one "y" coordinate. With a vector of numbers this could be a multiplication, with a vector of strings you want to use concatenation.
public static Matrix<T> CartesianProduct(Vector<T> vectorX, Vector<T> vectorY,
Func<T, T, T> combine)
{
// TODO: input not null; correct dimension
IEnumerable<T> combinations = vectorX.SelectMany(vectorY,
(xCoordinate, yCoordinate) => combine(xCoordinate, yCoordinate);
return new Matrix<T>(combinations);
}
Vector<string> abcArray = new Vector<string>(new string[] { "a", "b", "c" });
Vector<string> xyzArray = new Vector<string>(new string[] { "1", "2", "3" });
Matrix<string> m = Vector.CartesianProduct(abcArray, xyzArray, (x, y) => x + y);