So I created Pairs class that contains int and double and I want to create an array of them with my
array class by creating random values, but I'm getting System.NullReferenceException at Line 19 of
my array class.
Here's my pair class
class Pair
{
public int integer = 0;
public double doubl = 0.0;
public Pair(int integer, double doubl)
{
this.integer = integer;
this.doubl = doubl;
}
public Pair()
{
}
public int Integer() { return integer; }
public double Doubl() { return doubl; }
}
And this is my array class and the abstract class
class MyDataArray : DataArray
{
Pair[] data;
int operations = 0;
public MyDataArray(int n, int seed)
{
data = new Pair[n];
Random rand = new Random(seed);
for (int i = 0; i < n; i++)
{
data[i].integer = rand.Next(); //I get error here
data[i].doubl = rand.NextDouble();
}
}
public int integer(int index)
{
return data[index].integer;
}
public double doubl(int index)
{
return data[index].doubl;
}
}
abstract class DataArray
{
public int operations { get; set; }
public abstract void Swap(int i, int j);
public abstract void Swap2(int i, int high);
}
Also is it even worth it using this abstract class I used this from a reference that my university
provided. I have to create an quicksort algorithm that sorts pairs in arrays and linked lists and analyze it.
data = new Pair[n];
This creates a new array of null references.
The loop should be
for (int i = 0; i < n; i++)
{
data[i] = new Pair(rand.Next(), rand.NextDouble())
}
While we are looking at your code: you are making a good attempt here to make an immutable pair, but it could be better. What you want is:
class Pair
{
public Pair(int integer, double doubl)
{
this.Integer = integer;
this.Double = doubl;
}
public int Integer { get; private set; }
public double Double { get; private set; }
}
Shorter, safer, clearer.
The issue with your code is that you are only initializing the array of data in MyDataArray. When creating an array of instances, it only initializes references for the array, not the actual instances to be in the array. Those references all point to null. So when you do try to set the integer member of the i'th Pair instance in the data array:
...
data[i].integer = rand.Next();
...
You are actually trying to set the integer member of null, which does not exist.
...
null.integer = rand.Next();
...
To fix this, simply create a new instance of Pair for each index of data in your loop.
...
for (int i = 0; i < n; i++)
{
data[i] = new Pair();
data[i].integer = rand.Next();
data[i].doubl = rand.NextDouble();
}
...
Even better, you can use the constructor you've made where it takes parameters to set integer and doubl upon construction to simplify the code in your loop.
...
for (int i = 0; i < n; i++)
{
data[i] = new Pair(rand.Next(), rand.NextDouble());
}
...
Related
Why is it possible to set a 2d array even if the setter not implemented?
Here's my code.
public static void Main()
{
var obj = new TestObj();
obj.qwe[0, 0] = 6;
obj.asd = 7; //error
Console.WriteLine(obj.qwe[0, 0]); //6
}
public class TestObj
{
public int[,] qwe { get; } = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
public int asd { get; } = 4;
}
Why is it possible to set a 2d array even if the setter not implemented?
Because you aren't setting the property, you are updating an item in the array.
For example, this wouldn't compile:
obj.qwe = new int[0, 0];
In your code, you are calling get to obtain a reference to the array, and updating the item at index 0, 0:
obj.qwe[0, 0] = 6;
The property qwe is returning the reference to the array contents. The same applied to 1D or multi-dim arrays. All arrays in C# follow reference semantics
Consider the following
int[,] temp = obj.qwe; // property get
temp[0,0] = 6;
// obj.qwe[0,0] == 6
To prevent this from happening you need to create a wrapper class to the 2D array and implement an indexer.
class Program
{
static void Main(string[] args)
{
IntArray obj = new int[,] { { 1, 2 }, { 3, 4 } };
int x = obj[0, 0]; // ok, getter defined
obj[0, 0] = 10; // error, no setter defined
int[,] objCopy = obj; // assignment to int[,] makes a copy
objCopy[0, 0] = 10; // ok to modify copy
}
}
Use the integer array wrapper class below:
public class IntArray
{
readonly int[,] data;
public IntArray(int rows, int columns)
{
this.data = new int[rows, columns];
this.Rows = rows;
this.Columns = columns;
}
public IntArray(int[,] data)
{
this.data = data;
this.Rows = data.GetLength(0);
this.Columns = data.GetLength(1);
}
public int this[int row, int column]
{
// indexer getter
get => data[row, column];
}
public int Rows { get; }
public int Columns { get; }
public int[,] ToArray()
{
int[,] copy = new int[Rows, Columns];
Array.Copy(data, copy, data.Length);
return copy;
}
public static implicit operator IntArray(int[,] array)
=> new IntArray(array);
public static implicit operator int[,](IntArray obj)
=> obj.ToArray();
}
The reason why this is the case has already been answered by others.
To make the property read only I would suggest creating your own class for 2D arrays. This allow you to implement a read only interface, and it is fairly easy to do:
public interface IReadOnlyArray2D<out T>
{
T this[int x, int y] { get; }
}
public class MyArray2D<T> : IReadOnlyArray2D<T>
{
public int Width { get; }
public int Height { get; }
public T[] Data { get; }
public MyArray2D(int width, int height )
{
this.Width = width;
this.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;
}
}
There are other advantages of using a regular 1D array as the backing storage:
Sometimes you only want to process all items, and do not care about the x/y coordinates.
Multidimensional arrays can sometimes be slow if it is used incorrectly.
Interoperability is often easier since more systems use 1D arrays or pointers when exchanging data.
creating a multidimensional array like new T[width, height] will store it in column-major order, while most image-like data is usually stored row-major order.
I have a class as below,
class EUInput
{
public EUInput()
{
RtID = 0;
}
public int RtID { get; set; }
}
I want to store this class with different RtID values in a list. I tried as below,
static void Main(string[] args)
{
EUInput clsEUInput = new EUInput();
List list = new List();
for (int i = 0; i < 5; i++)
{
clsEUInput.RtID = i;
list.Add(clsEUInput);
}
foreach (EUInput obj in list)
{
Console.WriteLine(obj.RtID.ToString());
}
Console.ReadLine();
}
I am getting an output as
4
4
4
4
4
But I need an outupt as
0
1
2
3
4
You need to move the declaration of clsEUInput inside the for loop. Right now, there is only one EUInput object and you're adding the same object to the list multiple times.
List list = new List();
for (int i = 0; i < 5; i++)
{
EUInput clsEUInput = new EUInput();
clsEUInput.RtID = i;
list.Add(clsEUInput);
}
Change EUInput to be a struct (and keep your Main method as it is):
public struct EUInput
{
public int RtID;
}
A struct is a value type (a class is a reference type), so when you add it to a list, you basically add a "copy" of the whole structure (and not just a reference). So when you keep changing the RtID in the loop, you still change that one object you created, but the objects in the list won't be affected.
Either your boss is playing a trick on you, i.e. want's to test your knowledge about value types and reference types, or he doesn't know about the difference between them himself...
you Need new instances to the class
or the complete list will hold references to the one instance
private class EUInput
{
public EUInput()
{
RtID = 0;
}
public int RtID { get; set; }
}
//I want to store this class with different RtID values in a list. I tried as below,
private static void Main(string[] args)
{
List<EUInput> list = new List<EUInput>();
for (int i = 0; i < 5; i++)
{
EUInput clsEUInput = new EUInput();
clsEUInput.RtID = i;
list.Add(clsEUInput);
}
foreach (EUInput obj in list)
{
Console.WriteLine(obj.RtID.ToString());
}
Console.ReadLine();
}
I would like to create an array of objects. Each object has it's own int array.
For each object I assign values to it's array ONLY with keys given by myself (example: li[i].V[10] = 1; li[i].V[50] = 10; )
Can someone tell me how to do that? Can I do that without using Lists?
The second case is analogical to first. I would like to know how to assign values of object's List
using setter.
I tried to do that by myself. Unfortunately My code crashed cuz I don't know how to set the dimension of V and Word:
class CFiles
{
//private int[] v=new int[5];//dont want to specify the dimention of array here
private int[] v;//vector of file
private List<string> words;
public CFiles()
{
words = Words;
v = new int[50];
v = V;
}
public int[] V { get; set; }
public List<string> Words { get; set; }
}
class Program
{
static void Main(string[] args)
{
CFiles[] li = new CFiles[2];
for(int i=0;i<li.Length;i++)
{
li[i]=new CFiles();
li[i].V[10] = 1;
li[i].V[50] = 10;
li[i].V[50] = 15;
li[i].Words.Add("a");
li[i].Words.Add("ab");
li[i].Words.Add("abc");
}
for (int i = 0; i < li.Length; i++)
{
for(int j=0;j<li[i].V.Length;j++)
{
Console.WriteLine(li[i].V[j]);
}
}
Console.WriteLine();
}
}
Your constructor isn't right and your properties aren't quite right. You might want something more like this:
class CFiles
{
//private int[] v=new int[5];//dont want to specify the dimention of array here
private int[] v;
public int[] V { get { return v; } set { v = value; } }
private List<string> words;
public List<string> Words { get { return words; } set { words = value; } }
public CFiles()
{
words = new List<string>();
v = new int[51]; //needs to be 51 if you are going to assign to index 50 below
}
}
Other than those issues, your code seems to do what you want. You have an array of objects where each object has its own int array (in addition to a string of strings).
Is that not what you want?
Here is the code snippet from my LinqPad:
public class Elephant{
public int Size;
public Elephant()
{
Size = 1;
}
}
public struct Ant{
public int Size;
}
private T[] Transform2AnotherType<T>(Elephant[] elephantList)
where T:new()
{
dynamic tArray = new T[elephantList.Length];
for (int i = 0; i < elephantList.Length; i++)
{
tArray[i] = new T();
tArray[i].Size = 100;
//tArray[i].Dump();
}
return tArray;
}
void Main()
{
var elephantList = new Elephant[2];
var elephant1 = new Elephant();
var elephant2 = new Elephant();
elephantList[0] = elephant1;
elephantList[1] = elephant2;
elephantList.Dump();
var r = Transform2AnotherType<Ant>(elephantList);
r.Dump();
}
I want to change one object array of known type,Elephant,to another object array of type T. T is not a class,but limited to struct which
provided by the already existed API.And every instance of type T shares some common property,says Size,but also has their own particular property which
I have omitted in my example code.So I put dynamic keyword inside the Transform2AnotherType<T>.
And I could not even to use Dump to make sure if the assignment has made effect,thus will throw RuntimeBinderException.
My question is: how to correctly make the assignment in such a struct array and return it back properly?
I suggest change your code like this:
public class Elephant
{
public Elephant()
{
Size = 1;
}
public int Size { get; set; }
}
public struct Ant
{
public int Size { get; set; }
}
private static T[] Transform2AnotherType<T>(Elephant[] elephantList)
where T : new()
{
T[] tArray = new T[elephantList.Length];
for (int i = 0; i < elephantList.Length; i++)
{
dynamic arrayElement = new T();
arrayElement.Size = 100;
tArray[i] = arrayElement;
//tArray[i].Dump();
}
return tArray;
}
static void Main()
{
var elephantList = new Elephant[2];
var elephant1 = new Elephant();
var elephant2 = new Elephant();
elephantList[0] = elephant1;
elephantList[1] = elephant2;
//elephantList.Dump();
var r = Transform2AnotherType<Ant>(elephantList);
//r.Dump();
}
I initiated a multidimensional array:
private byte[,] grid = new byte[9, 9];
I want to hold a byte List with some values, for each cell withing the existing grid.
I know a 3 dimensional array would be handy here. But since the list with invalid values is dynamical, I would like to use a List instead of an array.
Edit: To give some context here. I'm making a sudoku, which is represented by a multidimensional array. Since I would like to solve the sudoku programmatically and I'm using the backtrack algorithm, I need to remember the digits that where invalid for each cell.
So each cell should consist of a value and a List. I could probably just put the actual field as first value in the list. But never know if there is an actual clean solution :)
var grid = new List<byte>[9,9];
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
grid[i, j] = new List<byte>();
After that every item of 9x9 array contains an empty List<byte>.
However, I would suggest creating a class like Field
public class Field
{
public byte Value { get; set; }
public List<byte> List { get; set; }
public Field()
{
List = new List<byte>();
}
}
And use it instead of just List<byte>:
var grid = new Field[9, 9];
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
grid[i, j] = new Field();
If I understand you correctly you need a list of bytes in a list?
Try this:
List<List<byte>> listOfBytesInList = new List<List<byte>>();
Update
You can implement a own class that uses internal a list of bytes.
I'm too late, but regardless I post my solution anyway.
public class ByteFieldList
{
private readonly List<byte> _interalBytes;
public ByteFieldList()
: this(4, 0)
{
}
public ByteFieldList(byte fieldValue)
: this(4, fieldValue)
{
}
public ByteFieldList(int capacity, byte fieldValue)
{
FieldValue = fieldValue;
_interalBytes = new List<byte>(capacity);
}
public byte FieldValue { get; set; }
public ByteFieldList Add(byte b)
{
_interalBytes.Add(b);
return this;
}
public void AddRange(byte[] bytes)
{
foreach (var b in bytes)
Add(b);
}
public ByteFieldList Remove(byte b)
{
_interalBytes.Remove(b);
return this;
}
public byte this[int index]
{
get { return _interalBytes[index]; }
}
public byte[] GetAllInvalid()
{
return _interalBytes.ToArray();
}
}
public void Usage()
{
ByteFieldList byteFieldList = new ByteFieldList(5);
byteFieldList.Add(5).Add(4).Add(8);
byteFieldList.AddRange(new byte[] { 7, 89, 4, 32, 1 });
var invalids = byteFieldList.GetAllInvalid(); // get 5, 4, 8, 7, 89, 4, 32, 1
byteFieldList.FieldValue = 4;
}