1

Problem

I am writing a Matrix class in C# and I know that this class needs a two dimension array to store the Matrix object. The constructor for my Matrix class takes two parameters, the m and n dimensions of the Matrix. I have tried to assign the array inside the constructor but I get the error that Invalid Rank Specifier. The code I tried is listed below.

class Matrix
    {
        //make the dimensions private
        private int m,n;

        //The Matrix constructor needs two parameters
        //The row and column dimensions
        //declare the two dimension array
        private int[][] array;
        public Matrix(int m, int n) {
          //assign the array inside the constructor
            array = new int[m][n];
        }
        //method to allocate the Matrix
    }

My goal is to initialize the array with the dimensions first so that assigning can be done without errors, Thank You.

 
Son of Man
  • 1,213
  • 2
  • 7
  • 27

3 Answers3

4

I feel like what you are trying to do is create a multi dimensional array, which you can learn more about here.

In your case this would mean that you would create an int[,] array as such:

class Matrix
{
    //make the dimensions private
    private int m,n;

    //The Matrix constructor needs two parameters
    //The row and column dimensions
    //declare the two dimension array
    private int[,] array;
    public Matrix(int m, int n) {
      //assign the array inside the constructor
        array = new int[m, n];
    }
    //method to allocate the Matrix
}

After that you can access your values through:

public int GetValue(int m, int n) => array[m,n];

And equally for settings values:

public void SetValue(int m, int n) => array[m,n] = value;
Foitn
  • 604
  • 6
  • 25
  • Okay, can you edit the method for setting values to use a loop, i just want to understand how the iteration is performed to achieve a successful assignment – Son of Man Nov 03 '21 at 07:53
  • I tried to assign after creating a new Matrix object and i got an error that `cannot apply indexing with [] to an object of type Matrix`. I tried to assign like this `Matrix A = new Matrix(4,4)`; `A[0][0]=2;`Can you help me figure out why that is? – Son of Man Nov 03 '21 at 08:04
  • If you want to iterate through a multidimension array you can do: `for(int i = 0; i <= array.GetUpperBound(0); i++) { Console.WriteLine(array[i,0]) }` However if you want to iterate through all of dimensions and all elements you can do something likes this: `for(int i = 0; i < array.GetLength(0); i++) for(int x = 0; x < array.GetLength(1); x++)` – Róbert Pécz Nov 03 '21 at 08:06
  • @RóbertPécz, did you check the constructor in my Matrix class?The constructor is everything, I will use that to initialize the array outside the class – Son of Man Nov 03 '21 at 08:11
2

You actually have a jagged array, i.e. array of array: int[][], note that 2d array is int[,]

To initialize int[][] you have to create each inner array:

 public Matrix(int m, int n) {
   array = new int[m][];         // outer array of size m which

   for (int i = 0; i < n; ++i)   // contains
     array[i] = new int[n];      // arrays of length n 
 }

You can use Linq for shorter syntax:

 using System.Linq;

 ...

 public Matrix(int m, int n) {
   array = Enumerable
     .Range(0, m)
     .Select(_ => new int[n])
     .ToArray();
 }

Edit: Possible Matrix implementation:

  class Matrix {
    private int[][] array;

    public Matrix(int rows, int columns) {
      if (rows <= 0)
        throw new ArgumentOutOfRangeException(nameof(rows));
      if (columns <= 0)
        throw new ArgumentOutOfRangeException(nameof(columns));

      array = Enumerable
        .Range(0, rows)
        .Select(_ => new int[columns])
        .ToArray();
    }

    public int RowCount => array.Length;

    public int ColumnCount => array[0].Length;

    public int this[int row, int column] {
      get {
        if (row < 0 || row >= array.Length)
          throw new ArgumentOutOfRangeException(nameof(row));
        if (column < 0 || column >= array[row].Length)
          throw new ArgumentOutOfRangeException(nameof(column));

        return array[row][column];
      }
      set {
        if (row < 0 || row >= array.Length)
          throw new ArgumentOutOfRangeException(nameof(row));
        if (column < 0 || column >= array[row].Length)
          throw new ArgumentOutOfRangeException(nameof(column));

        array[row][column] = value;
      }
    }
  }
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • What is a jagged array? – Son of Man Nov 03 '21 at 07:58
  • Am trying to assign to the array and am getting this error, `Cannot apply indexing with [] to an object of type Matrix`, I tried assigning to a certain index like this `Matrix A = new Matrix(4,4); A[0][0] ` – Son of Man Nov 03 '21 at 08:00
  • @KINYUA TIMOTHY NJIRU: jagged array is an *array of arrays*: note that inner arrays can be of *different* lengths: `int[][] array = new int[][] {new int[] {1, 2, 3}, new int[] {4}, new int[] {5, 6}};` – Dmitry Bychenko Nov 03 '21 at 08:00
  • recheck my first comment, am getting an error trying to assign after creating a 4 by 4 array Matrix – Son of Man Nov 03 '21 at 08:01
  • Okay, my bad, l need to access the array inside the Matrix object and assign, How do we assign multidimension arrays? – Son of Man Nov 03 '21 at 08:29
  • @KINYUA TIMOTHY NJIRU: multidimensional array (2d array in your case) is declared as `int[,] array;`initialized as `array = new int[m, n];` addressed as `array[y, x];`. Jagged array is decalared as `int[][] array;`, initialized as in my answer above, addressed as `array[y][x];` – Dmitry Bychenko Nov 03 '21 at 08:33
  • I did `A.array[0,0]=2` and it works for some reason, is this the same as `A[0][0]=2` in the same context but with other programming languages? – Son of Man Nov 03 '21 at 08:37
  • @KINYUA TIMOTHY NJIRU: it can work in some C language compilers – Dmitry Bychenko Nov 03 '21 at 09:10
  • Am lost, Is there a way to make the in-built Matrix class of the C# language accept two parameters am trying to do a transform and I need to access the inverse of a matrix which I have realized my current class does not have? namespace `System.Drawing.Drawing2D.Matrix` – Son of Man Nov 03 '21 at 09:32
  • @KINYUA TIMOTHY NJIRU: I've provided simple `Matrix` implementation; note that if you want *inverse* matrix you should operate with *floating point* values. – Dmitry Bychenko Nov 03 '21 at 09:46
2

I prefer to use a regular 1D array for 2D data. Something like:

public class MyMatrix<T> 
{
        public int Width { get; }
        public int Height { get; }
        public T[] Data { get; }
        public MyMatrix(int width, int height)
        {
            Width = width;
            Height = height;
            Data = new T[width * height];
        }
        public T this[int x, int y]
        {
            get => Data[y * Width + x];
            set => Data[y * Width + x] = value;
        }
}

This has some advantages over the typical 2D Multidimensional approach:

  • Interoperability: Multidimensional arrays are a .Net concept that does not exist in every language, but just about every language have some sort of 1D array.
  • Serialization: Most serialization libraries handle 1D arrays, support for 2D arrays are more spotty.
  • Performance: Sometimes you just need to iterate over all the items, using the backing 1D arrays is probably the fastest way to do this.
  • Avoiding pitfals: .GetLength() for multidimensional arrays is quite slow, not a large problem if you cache the values outside your loop, but can be a problem if you do not know about this, or forget.
JonasH
  • 28,608
  • 2
  • 10
  • 23
  • Wow, trying this out, looks safe and easy to implement, am having an issue with the assignment of a certain index `A[0][0]` in the array, compiler says `cannot apply indexing with [] to an object of type Matrix`, I hope your code will work. – Son of Man Nov 03 '21 at 08:07
  • What version of .Net does this run on again, am getting an error in the getters and setters that only specific `assignment, call, increment, decrement, call can be used as statement` – Son of Man Nov 03 '21 at 08:10
  • 1
    @KINYUA TIMOTHY NJIRU indexing is done like `[x, y]` not `[x][y]`. Not sure about the error, but it will require c# 7 for the expression bodied properties, but you should be able to just use regular setters/getters. I.e. `get{return Data[y * Width + x];}` – JonasH Nov 03 '21 at 08:39
  • you know you need to edit your answer so it becomes easier for me – Son of Man Nov 03 '21 at 08:42
  • 2
    @KINYUA TIMOTHY NJIRU the example code is perfectly fine as it is in any recent version of c#. I do not see it as very helpful overall to use examples using first version of the language since it lacks even basic features like generics. – JonasH Nov 03 '21 at 08:47