C# Collection initialization syntax for use with custom matrix class?

477 views Asked by At

I'm creating a custom matrix class that only has a single 2D array to hold everything (I know that a 1D array is faster and better, but that's not the point of this implementation) the thing is, I'd like to have a constructor, and be able to do something like

Matrix a = new Matrix(2,2){{1,2},{3,4}};

and have it all work out. I've run into the "'Matrix' does not contain a definition for 'Add' and no extension method 'Add' etc." but after looking around, I've yet to be able to find robust enough info on how to define the Add() method in order to make it work. Here's the code I have so far

public class Matrix : IEnumerable
    {
        /* What we know abuot matricies
         * - matricies are defined by rows, cols
         * - addition is element-wise
         */

        public IEnumerator GetEnumerator()
        {
            yield return m;
        }

        private void Add(double a)
        {
            // what exactly should go here anyway?
        }

        private double[,] m;

        public double this[int rows, int cols]
        {
            get => m[rows, cols];
            set => m[rows, cols] = value;
        }       

        public Matrix(int rows, int cols)
        {
            m = new double[rows, cols];
        }
    ...
    }

so, how would I go about doing the Add() method anyway?

3

There are 3 answers

3
Magnetron On BEST ANSWER

Try this code. Your Add method must be public. Also, to make the code safe, you must add verifiers to check if the sizes of the m matrix and the provided data match.

private int currentRow = 0;
public void Add(params double[] a)
{
    for (int c = 0; c < a.Length; c++)
    {
        m[currentRow, c] = a[c];
    }
    currentRow++;
}

If you don't provide all the rows, the remaining rows will have the elements with their defaults values. Also, note that this method can be called in the future, and it would throw an exception when the m matrix has all the rows filled.

1
John Wu On

Magnetron's answer is the way to do it if you want to use the collection initializer syntax. This would work better with a jagged array instead of a two-dimensional array; as he points out, it's not possible to do a compile time check to ensure that the number of arguments in the initializer matches the size of the matrix, so you're going to risk runtime errors just initializing the class.

Another approach would be to implement an alternative constructor that allows you to initialize the matrix, like this:

public Matrix(double[,] source)
{
    m = source;
}

Then your line of code would look like this:

Matrix a = new Matrix(new double[,]{ {1,2},{3,4} });

This would avoid the issue since the dimensions of the matrix are determined by the dimensions of the initialization data, which must be a two-dimensional array.

1
Carlos On

I know I am late, but what about an extension method of double[,], or even implementing an implicit cast?

class Matrix
{
    // Implicit cast
    public static implicit operator Matrix(double[,] array) => new Matrix(array);

    private double[,] source;
    public Matrix(double[,] source)
    {
        this.source = source;
    }
}
static class Extensions
{
    // Extension
    public static Matrix ToMatrix(this double[,] array)
    {
        return new Matrix(array);
    }
}
static class Program
{
    static void Main()
    {
        // Extension
        Matrix a = new double[,] {
            { 1.0, 2.0, 3.0 },
            { 1.0, 2.0, 3.0 },
            { 1.0, 2.0, 3.0 }
        }.ToMatrix();

        // Implicit cast
        Matrix b = new double[,] {
            { 1.0, 2.0, 3.0 },
            { 1.0, 2.0, 3.0 },
            { 1.0, 2.0, 3.0 }
        };
    }
}