note: BJ Myers comment was useful and was the answer in fact. However, as it was a comment, I couldn't mark that as an answer but I've placed the corrected code (using his advice) at the end of this question.
Original question below continues:
This situation may look weird at first but here is what I intend to do:
Similar to the syntax in Python, instead of creating a multidimensional array (a 2-d array, to be exact), I want to create an array of arrays (a vector of vectors, in fact).
I'm aware that C# will not let me create pointers in safe code, but I'm still curious whether there is a safer way to accomplish this task w/o getting of the safe code limits.
So, I came up with the code below but couldn't figure out how to extract a specific row from the array (as shown between the comment lines).
Is it possible to pass the r'th row at once or do I need to create another temporary storage for r'th row and then pass that temporary vector through?
(System: Windows-10, VS-2013, C#)
using System;
public class Vector {
public double[] data;
public Vector(double[] data) {
this.data = new double[data.GetLength(0)];
this.data = data;
}
}
public class Matrix {
private int row, col;
public Matrix(double[,] data) {
this.row = data.GetLength(0);
this.col = data.GetLength(1);
Vector[] v = new Vector[this.row];
for (int r = 0; r < this.row; r++) {
// ****** this line below ******
v[r] = new Vector(data[r,???]);
// ****** how to extract the r'th row ******
}
}
static void Main(string[] args) {
double[,] data = { { 9.0, 8.0, 7.0 }, { 5.0, 6.0, 4.0 }, { 3.0, 2.0, 2.0 } };
Matrix A = new Matrix(data);
Console.ReadLine();
}
}
The corrected code is below:
using System;
public class Vector {
public double[] data;
public Vector(double[] data) {
this.data = new double[data.GetLength(0)];
this.data = data;
for (int i = 0; i < data.GetLength(0); i++) {
Console.Write("{0: 0.000 }", this.data[i]);
}
Console.WriteLine();
}
}
public class Matrix {
private int row, col;
public Matrix(double[][] data) {
this.row = data.GetLength(0);
this.col = data[0].GetLength(0);
Vector[] v = new Vector[this.row];
for (int r = 0; r < row; r++) {
v[r] = new Vector(data[r]);
}
Console.WriteLine("rows: " + this.row.ToString());
Console.WriteLine("cols: " + this.col.ToString());
}
static void Main(string[] args) {
double[][] data = { new double[] { 9.0, 8.0, 7.0 },
new double[] { 5.0, 6.0, 4.0 },
new double[] { 3.0, 2.0, 2.0 } };
Matrix A = new Matrix(data);
Console.ReadLine();
}
}
Well, you want to make an array class and acess like one? Make an indexer. what is an indexer? - it's a way to make your class accessible like an array.
Look over the link for examples, I'll help you with your specific case.
public class Vector {
public double[] data;
public double this[int i]
{
get
{
// This indexer is very simple, and just returns or sets
// the corresponding element from the internal array.
return data[i];
}
set
{
data[i] = value;
}
}
public Vector(double[] data) {
this.data = new double[data.GetLength(0)];
this.data = data;
}
}
once it's defined like so, this is perfectly valid:
double elementArray = new double[data.GetLength(1)]; // declaring an array, the size of the second dimention of the data array.
for(int i =0; i<data.GetLength(1);i++)
{
elementArray[i] = data[r,i]; // adding all the elements to the list
}
v[r] = new Vector(elementArray);
EDIT: BJ Myers' comment is right, this solution works perfectly for a jagged array too, but make sure that you declare it properly like he mentioned.
EDIT 2: Using a list is pointless here, changed the stracture to an array.
Related
I am trying to use Index and Range objects to slice a jagged array. But in the example below I cannot extract columns, only rows.
var A = new float[3][];
A[0] = new float[] { 1.1f, 1.2f, 1.3f };
A[1] = new float[] { 2.1f, 2.2f, 2.3f };
A[2] = new float[] { 3.1f, 3.2f, 3.3f };
// This works as intended to extract rows
var A_row1 = A[0][..]; // { 1.1, 1.2, 1.3 }
var A_row3 = A[^1][..]; // { 3.1, 3.2, 3.3 }
var A_row23 = A[1..^0][..]; // { { 2.1, 2.2, 2.3}, { 3.1, 3.2, 3.3 } }
// This does not work as intended to extract columns
var A_col1 = A[..][0]; // { 1.1, 1.2, 1.3 } ** WRONG
var A_col3 = A[..][^1]; // { 3.1, 3.2, 3.3 } ** WRONG
var A_col23 = A[..][1..^0]; // { { 2.1, 2.2, 2.3}, { 3.1, 3.2, 3.3 } } ** WRONG
var A_sub22 = A[0..2][0..2];
// { { 1.1, 1.2, 1.3 }, { 2.1, 2.2, 2.3 } } ** WRONG
// { { 1.1, 1.2 }, { 2.1, 2.2 } } <= WHAT I AM EXPECTING
Why is it that A[..][0] returns the exact same result as A[0][..]? And why doesn't the last statement contain 2 columns per row, but 3?
The bigger picture here is that I am building a Matrix object that stores the numeric data in a jagged array of double and I want to implement slicing using Index and Range. I thought I could have it support slicing with the following methods
public class Matrix
{
readonly double[][] Elements;
///<summary>Reference a single element</summary>
public ref double this[Index row, Index column]
=> ref Elements[row][column];
///<summary>Extract a sub-matrix</summary>
public double[][] this[Range rows, Range columns]
=> Elements[rows][columns];
///<summary>Extract a row sub-vector</summary>
public double[] this[Index row, Range columns]
=> Elements[row][columns];
///<summary>Extract a column sub-vector</summary>
public double[] this[Range rows, Index column]
=> Elements[rows][column];
}
But this failed spectacularly in my unit testing. It seems that even if C# supports the syntax, the results are unexpected.
Is there a way to implement the functionality I want to have using the existing framework for slicing that C# is trying to implement?
Sorry, I come from a Fortran background where slicing is natural.
Also, am I the only one that finds it very confusing that the last element in an array is indexed as [^1] but the range to the last element is [..^0]. It seems very inconsistent on the part of Microsoft to have ^0 mean different things for Index as it does for Range.
The columns are three different arrays. The slicing operators do not work across those different arrays, only within one array.
The only slicing you are doing is on the row array and returns the column arrays according to the operators.
A[0][..] returns the first array of A (which is the first column). [..] then returns the whole column.
A[..][0] returns the whole array (which is A again) and then the first entry in A, which is again the first column.
This is how I implemented slicing and injecting with a jagged array as extension methods
public static class Extensions
{
public static TData Slice<TData>(this TData[][] matrix, Index row, Index column)
{
return matrix[row][column];
}
public static TData[] Slice<TData>(this TData[][] matrix, Index row, Range columns)
{
var slice = matrix[row];
return slice[columns];
}
public static TData[] Slice<TData>(this TData[][] matrix, Range rows, Index column)
{
var slice = matrix[rows];
var result = new TData[slice.Length];
for (int i = 0; i < result.Length; i++)
{
result[i] = slice[i][column];
}
return result;
}
public static TData[][] Slice<TData>(this TData[][] matrix, Range rows, Range columns)
{
var slice = matrix[rows];
for (int i = 0; i < slice.Length; i++)
{
slice[i] = slice[i][columns];
}
return slice;
}
public static void Inject<TData>(this TData[][] matrix, Index row, Index column, TData value)
{
matrix[row][column] = value;
}
public static void Inject<TData>(this TData[][] matrix, Index row, Range columns, TData[] values)
{
int n = matrix.Length;
int m = matrix.Max((row)=>row.Length);
(int offset, int count) = columns.GetOffsetAndLength(m);
var slice = matrix[row];
var data = new ReadOnlySpan<TData>(values);
var span = new Span<TData>(slice, offset, count);
data.CopyTo(span);
}
public static void Inject<TData>(this TData[][] matrix, Range rows, Index column, TData[] values)
{
var slice = matrix[rows];
for (int i = 0; i < slice.Length; i++)
{
slice[i][column] = values[i];
}
}
public static void Inject<TData>(this TData[][] matrix, Range rows, Range columns, TData[][] values)
{
int n = matrix.Length;
int m = matrix.Max((row)=>row.Length);
(int offset, int count) = columns.GetOffsetAndLength(m);
var slice = matrix[rows];
for (int i = 0; i < slice.Length; i++)
{
var data = new ReadOnlySpan<TData>(values[i]);
var span = new Span<TData>(slice[i], offset, count);
data.CopyTo(span);
}
}
}
I am trying to insert data into a 2D array of objects from a csv file but I have problems with initializing the 2D array of objects, and I get this error message:
IndexOutOfRangeException: Index was outside the bounds of the array.
UPDATE:
I think the problem is with Initializing the array of object , because I tried to insert data manually without using CSV file like this code below and still having the same error message :
UPDATE No.2 :
I tried to Simplify the code by making 1 object only but still cant insert data
Simplified code :
public CoreManager mng = new CoreManager();
void Start()
{
mng.actual_words[1] = "n"; //-> the problem I'm facing is on this line
Debug.Log(mng.actual_words[1]);
}
Here is my code trying to insert data from csv file :
public class NewBehaviourScript : MonoBehaviour
{
int sentenceNumber = 0;
int storynumber = 0;
public CoreManager[][] mng = new CoreManager[5][];
void Start()
{
TextAsset questdata = Resources.Load<TextAsset> ("first_storytest");
string[] data = questdata.text.Split(new char[] { '\n' });
Debug.Log(data.Length);
for (int i = 1; i < data.Length - 1; i++)
{
string[] row = data[i].Split(new char[] { ',' });
for(int x = 0; x < row.Length; x++)
{
if (row[x] != "")
{
if (row[x] == "***")
{
storynumber++;
sentenceNumber = 0;
}
else
{
mng[storynumber][sentenceNumber].actual_words[x] = row[x];
}
}
}
sentenceNumber++;
}
}
}
Here is my code trying to insert one item manually :
int sentenceNumber = 0;
int storynumber = 0;
public CoreManager[][] mng = new CoreManager[5][];
void Start()
{
mng[storynumber][sentenceNumber].actual_words[1]="test1";
}
public class CoreManager
{
[Tooltip("Write these words in actual sequence of the sentence")]
public string[] actual_words;
[Tooltip("Write these words in any sequence of the sentence")]
public string[] mixed_words;
}
This line of code only allows 5 entries in one dimension but doesn't allocate any space for the other direction. If you're using arrays, you need to provide the size up front.
public CoreManager[][] mng = new CoreManager[5][];
For testing purposes, I'd set the mng to [100][100] and use a small csv and see if this fixes your problem. If it does, then that's definitely the problem. If it doesn't, then something else is wrong.
Edit: After reviewing this some more, I'd suggest changing your data structure to use Dictionaries instead. This will provide more flexibility at runtime.
2nd Edit:
Or you can go with a multidemensional array which has a different syntax.
Feel free to run this example for yourself:
public static void Main()
{
Console.WriteLine("Lets get started!");
int[,] mng = new int[5,5];
mng[0,0] = 5;
Console.WriteLine(mng[0,0]);
}
// Output:
// Lets get started!
// 5
Cbooks has an atribute "CTeam[] Teams" and it is of fixed size (8). If I want to add objects to it using this in the Main:
CBook A1 = new CBook("Title1", "Author1");
CBook A2 = new CBook("Title1", "Author2");
CBooks ArrayOfBooks = new CBooks(8);
ArrayOfBooks.Add(A1);
ArrayOfBooks.Add(A2);
then position 0 and 1 are ocuppied, and the positions from 2 to 7 are null. What I want to do is, using a variable "int aux=0", count the ocupied positions like this:
for (int k = 0; k < NumberOfTeams; k++)
{
if (Teams[k].Name=="")
Aux += 1;
}
So, Aux in this case would be 2, then I want to do "Teams[Aux] = A" so that A would be in the position 2 and now I should have three objects in my array. But I'm getting "Index out of bound"
Your implementation then should look similar to this:
public class Program
{
public static void Main(string[] args)
{
Element a = new Element("A");
Element b = new Element("B");
MyArray array = new MyArray(8);
array.Add(a);
array.Add(b);
Console.WriteLine(array.Count()); //2 Elements are in the array
}
}
//Sample element class.
public class Element{
public readonly String MyString;
public Element(String myString){
MyString = myString;
}
}
//Sample array class.
public class MyArray{
private readonly Element[] myArray;
private int count; //Use a property here
public MyArray(int size){
//Be careful -> check if size is >= 0.
myArray = new Element[size];
}
public bool Add(Element element){
if(myArray.Length == count) // return false if no more elements fit.
return false;
myArray[count] = element;
count++;
return true;
}
public int Count(){
return count;
}
}
So there is no need for creating an extra count loop. Your "count" variable in "MyArray" class holds always the correct value.
Anyway the implementation or use case of this code is a little bit clunky.
Why are you cant use directly a more safe list or something. That would be a better solution.
What do you need CBooks for? From what I understand, it's just an array of 8 CBook objects so why not use CBook[]?
CBook A1 = new CBook("Title1", "Author1");
CBook A2 = new CBook("Title1", "Author2");
CBooks[] ArrayOfBooks = new CBook[8];
ArrayOfBooks[0] = A1;
ArrayOfBooks[1] = A2;
int aux = 0;
for (int k = 0; k < ArrayOfBooks.Length; k++)
{
//break the loop because we know there are no more books
if (ArrayOfBooks[k] == null)
break;
aux++;
}
The question doesn't cover what the variables NumberOfTeams and Teams are for but could those be added to the implementation of CBook?
I have a class called Matrix : IEnumerable<double>, (classic, mathematical matrix. It is basically a 2D array with some goodies).
The class is immutable, so there is no way to change its values after instance creation.
If want to create a matrix with pre-existing values I have to pass an array to the constructor like this:
double[,] arr = new double[,]
{
{1,2,3}, {4,5,6}, {7,8,9}
};
Matrix m = new Matrix(arr);
Is there a way to turn it into this: (?)
Matrix m = new Matrix
{
{1,2,3}, {4,5,6}, {7,8,9}
};
Update:
Found a hack-ish way yo make it work. I'm not sure if this solution is advisable, but it works.
class Matrix : ICloneable, IEnumerable<double>
{
// Height & Width are initialized in a constructor beforehand.
/*
* Usage:
* var mat = new Matrix(3, 4)
* {
* {1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}
* };
*/
int rowIndex;
bool allowArrayInitializer;
double[,] tempData;
double[,] data;
public void Add(params double[] args)
{
if(!allowArrayInitializer)
throw new InvalidOperationException("Cannot use array initializer");
if(args.Length != Width || rowIndex >= Height)
throw new InvalidOperationException("Invalid array initializer.");
for(int i = 0; i < Width; i++)
tempData[i, rowIndex] = args[i];
if(++rowIndex == Height)
data = tempData;
}
}
Not if it’s immutable; that syntactic sugar is implemented using Add().
You will not able to do it via initializer but should be able to do it via parameterized constructor.
You can see the sample code below :
class Matrix : IEnumerable<double>
{
double[,] input;
public Matrix(double[,] inputArray)
{
input = inputArray;
}
public IEnumerator<double> GetEnumerator()
{
return (IEnumerator<double>)input.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return input.GetEnumerator();
}
}
In the main method :
static void Main(string[] args)
{
var m = new Matrix(new double[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } });
}
I hope this helps you!
instead of deriving from IEnumerable I would use a property:
class Matrix
{
public double[,] Arr { get; set; }
}
Matrix m = new Matrix
{
Arr = new double [,] { {1d,2d,3d}, { 4d,5d, 6d}}
};
I would like to define an array of array eg int[][] on top of an existing int[] of the right size. I want then to seamlessy use either the int[][] array of array or the int[] 'big' array while refering to the same inner data.
Is this possible to do this in C# using unmanaged code? In C++ I would defined pointers like this :
int* bigArray = new int[numberOfRows * numberOfColumns];
int** matrix = new int*[numberOfRows];
for (int i = 0; i < numberOfRows; i ++)
{
matrix[i] = (bigArray + i * numberOfColumns);
}
Yes, you can also use pointer in C#, but there are some limits on it. 1st, you need to declare the function with unsafe, and also, you need to set the build option to allow unsafe code in the project property, here is the sample code about it:
unsafe static void T1(int numberOfRows, int numberOfColumns)
{
int* bigArray = stackalloc int[numberOfRows * numberOfColumns];
int** matrix = stackalloc int*[numberOfRows];
for (int i = 0; i < numberOfRows; i++)
{
matrix[i] = (bigArray + i * numberOfColumns);
}
}
Remember, you can use the pointer only if you are so clear of that you have full control of your code. while it is not recommend you use the pointer in C#
You can do it in managed code, using a class as a wrapper and providing it with an indexer:
class Matrix
{
public readonly int[] BigArray; // make available
private int _rowSize = ...;
public int this[int x, int y]
{
get { return BigArray [x*_rowSize+y]; }
set { BigArray [x*_rowSize+y] = value; }
}
}
Edit:
changed arrray into public readonly field so that the class has a dual interface
Edit 2:
Using T[][] to provide access to T[] rows.
class Matrix2<T>
{
private T[][] _data;
private int _columns;
public Matrix2(int rows, int cols)
{
_data = new T[rows][];
_columns = cols;
for (int i = 0; i < rows; i++) _data[i] = new T[cols];
}
public T this [int x]
{
get { return _data [x/_columns][x % _columns]; }
set { _data [x/_columns][x % _columns] = value; }
}
public T[] Row(int r)
{
return _data [r];
}
}