I'm working with a vector class who have generic type like this
public class Vector<T>: IEnumerable<T>, IEnumerable
{
public T[] Array { get; private set; }
...
}
I want to create a Matrix class who have a vector list of generic types as property.
public class Matrix
{
public list<Vector<GenType>> Columns{get; set;}
}
Is that posible?
EDIT 1: It's a general purpose matrix class. Most of the methods needs the array performance so it is contained in the vector class. Even is used to take data from database so the multi-type is needed.
Actually is used with public list<Vector>.
CodePudding user response:
I would suggest you make an abstract base class Vector
and then inherit Vector<T>
from it. Then Matrix
doesn't need to be generic.
public class Matrix
{
public List<Vector> Columns { get; set; }
}
public abstract class Vector : IEnumerable
{
public abstract IEnumerator GetEnumerator();
public abstract Type GetScalarType();
}
public class Vector<T> : Vector, IEnumerable<T>
{
private T[] _array { get; set; }
public override IEnumerator GetEnumerator() =>
((IEnumerable<T>)_array).GetEnumerator();
public override Type GetScalarType() =>
typeof(T);
IEnumerator<T> IEnumerable<T>.GetEnumerator() =>
((IEnumerable<T>)_array).GetEnumerator();
}
You then might end with code like this:
if (vector is IEnumerable<int> values)
{
/* do stuff with `values` */
}
In general it should suffice.
CodePudding user response:
Of course, it is possible. Here the exact same thing I have done:
public readonly struct Vector<TNum> : ICollection<TNum>, System.Collections.ICollection
where TNum: INumberBase<TNum>
{
readonly TNum[] data;
#region Factory
public Vector(int size)
{
this.data = new TNum[size];
Size = size;
}
public Vector(params TNum[] data)
{
this.data = data.ToArray();
Size = this.data.Length;
}
public Vector(int size, Func<int, TNum> initalizer)
{
data = Enumerable.Range(0, size).Select(index => initalizer(index)).ToArray();
Size = data.Length;
}
public static implicit operator Vector<TNum>(TNum[] data) => new Vector<TNum>(data);
public static implicit operator TNum[](Vector<TNum> vector) => vector.ToArray();
#endregion
#region Properties
public TNum[] Data => data;
public int Size { get; }
public TNum this[Index index]
{
get => data[index];
set
{
data[index] = value;
}
}
public TNum[] this[Range range]
{
get => data[range];
set
{
var slice = data.AsSpan(range);
value.CopyTo(slice);
}
}
public Span<TNum> GetSpan(Index index) => data.AsSpan(index);
public Span<TNum> GetSpan(Range range) => data.AsSpan(range);
#endregion
#region Collection
public bool Contains(TNum item) => data.Contains(item);
public void CopyTo(TNum[] array, int arrayIndex) => data.CopyTo(array, arrayIndex);
public void CopyTo(Span<TNum> array, int arrayIndex) => data.AsSpan(arrayIndex).CopyTo(array);
public IEnumerator<TNum> GetEnumerator() => data.AsEnumerable().GetEnumerator();
public TNum[] ToArray() => data.Clone() as TNum[];
#endregion
}
and the generic matrix class
public readonly struct Matrix<TNum>
where TNum: INumberBase<TNum>
{
readonly Vector<TNum>[] data;
#region Factory
public Matrix(int rows, int columns)
{
Rows = rows;
Columns = columns;
this.data = new Vector<TNum>[rows];
for (int i = 0; i < data.Length; i )
{
data[i] = new Vector<TNum>(columns);
}
}
public Matrix(int rows, int columns, params TNum[] byRows)
{
Rows = rows;
Columns = columns;
this.data = new Vector<TNum>[rows];
for (int i = 0; i < data.Length; i )
{
data[i] = byRows.AsSpan(columns * i, columns).ToArray();
}
}
private Matrix(int rows, int columns, Vector<TNum>[] data)
{
Rows = rows;
Columns = columns;
this.data = data;
}
public Matrix(Vector<TNum>[] data)
{
Rows = data.Length;
Columns = data.Length > 0 ? data[0].Size : 0;
this.data = data.ToArray();
}
public Matrix(TNum[][] data)
{
Rows = data.Length;
Columns = data.Length > 0 ? data[0].Length : 0;
this.data = data.Select((row) => new Vector<TNum>(row)).ToArray();
}
public Matrix(int rows, int columns, Func<int, int, TNum> initializer)
{
Rows = rows;
Columns = columns;
this.data = new Vector<TNum>[rows];
for (int i = 0; i < data.Length; i )
{
this.data[i] = new Vector<TNum>(columns, (j) => initializer(i, j));
}
}
public static implicit operator Matrix<TNum>(TNum[][] matrix) => new Matrix<TNum>(matrix);
public static implicit operator Matrix<TNum>(Vector<TNum>[] data) => new Matrix<TNum>(data);
#endregion
#region Properties
public int Rows { get; }
public int Columns { get; }
public TNum this[Index row, Index column]
{
get => data[row][column];
set
{
data[row][column] = value;
}
}
public TNum[] this[Index row, Range columns]
{
get => data[row][columns];
set
{
var span = data[row].GetSpan(columns);
value.AsSpan().CopyTo(span);
}
}
public TNum[] this[Range rows, Index column]
{
get
{
var slice = data[rows];
TNum[] result = new TNum[slice.Length];
for (int i = 0; i < slice.Length; i )
{
result[i] = slice[i][column];
}
return result;
}
set
{
var slice = data[rows];
for (int i = 0; i < slice.Length; i )
{
slice[i][column] = value[i];
}
}
}
public TNum[][] this[Range rows, Range columns]
{
get
{
var slice = data[rows];
TNum[][] result = new TNum[slice.Length][];
for (int i = 0; i < slice.Length; i )
{
result[i] = slice[i][columns];
}
return result;
}
set
{
var slice = data[rows];
for (int i = 0; i < slice.Length; i )
{
slice[i][columns] = value[i];
}
}
}
public Vector<TNum> GetRow(Index row) => data[row];
public Vector<TNum>[] GetRows(Range rows) => data[rows];
public Vector<TNum> GetColumn(Index column)
{
TNum[] result = new TNum[data.Length];
for (int i = 0; i < data.Length; i )
{
result[i] = data[i][column];
}
return result;
}
public Vector<TNum>[] GetColumns(Range columns)
{
Vector<TNum>[] result = new Vector<TNum>[data.Length];
for (int i = 0; i < data.Length; i )
{
result[i] = data[i][columns];
}
return result;
}
public TNum[][] ToJaggedArray() => data.Select(row => row.ToArray()).ToArray();
#endregion
#region Collection
public bool Contains(TNum value) => data.Any((row) => row.Contains(value));
#endregion
}
I have skipped through all the algebra, and linear system solving, but it works great. I made the decision to make them a readonly struct
so that there is no chance for unintended modifications. Each vector/matrix is of fixed size, but their elements can be changed. I have implemented Index
and Range
indexing to facilitate slicing. For example: x[1..3]