How to prevent overriding array entries in a for-loop? - c#

I got the hint for my program to make it easier to read and maintenance with using class structures instead of a mass of arrays and matrices. (I didn't find similar topics here, but maybe I used the wrong vocabulary. But although I hope to get help)
As I have a dataset with multiple entries I don't wanna have all of them but some specific ones. So I build a class to store them easier:
public class ControlPoint
{
// classify necessary variables
public double _collimatorangle;
public double _gantryangle;
public double[] _jawpositions = new double[4];
public double _monitorunits;
public double[] _mlcs = new double[120];
public double _beamenergy;
// construct the class
public ControlPoint()
{
}
}
Calling and filling them is not the problem but I have over 100 of those ControlPoint objects, so I wanted to use a for loop to fill them and store them in a new array/list/ArrayList. In the end, I would like to use the data for calculating differences but converting this class into double doesn't work. So I wrote this
ControlPoint[] DataPoints = new ControlPoint[160];
ControlPoint CoPos = new ControlPoint();
for (int j = 0; j < 160; j++)
{
// reading data from file
// ...
CoPos._jawpositions[0] = Convert.ToDouble(ReadData_1);
CoPos._jawpositions[1] = Convert.ToDouble(ReadData_2);
CoPos._jawpositions[2] = Convert.ToDouble(ReadData_3);
CoPos._jawpositions[3] = Convert.ToDouble(ReadData_4);
DataPoints[j] = CoPos;
}
So after the loop, I expected a DataPoints array with different values for each array entry. But in Debugging I saw that changing the data e.g. at j = 10 all values in DataPoints from 0 to 9 change to the actual value.
I don't know where I did a wrong step and hope you can help me to prevent that overriding.

You're only creating one instance of ControlPoint and modifying it over and over, then assigning it to every element of the array. Move the instantiation inside the loop:
for (int j = 0; j < 160; j++)
{
ControlPoint CoPos = new ControlPoint();
// reading data from file
// ...
CoPos._jawpositions[0] = Convert.ToDouble(ReadData_1);
CoPos._jawpositions[1] = Convert.ToDouble(ReadData_2);
CoPos._jawpositions[2] = Convert.ToDouble(ReadData_3);
CoPos._jawpositions[3] = Convert.ToDouble(ReadData_4);
DataPoints[j] = CoPos;
}

You are assigning the same CoPos object to every element in your DataPoints array, only altering the value on every loop. Create a new object inside the loop:
ControlPoint[] DataPoints = new ControlPoint[160];
for (int j = 0; j < 160; j++)
{
// reading data from file
// ...
var CoPos = new ControlPoint();
CoPos._jawpositions[0] = Convert.ToDouble(ReadData_1);
CoPos._jawpositions[1] = Convert.ToDouble(ReadData_2);
CoPos._jawpositions[2] = Convert.ToDouble(ReadData_3);
CoPos._jawpositions[3] = Convert.ToDouble(ReadData_4);
DataPoints[j] = CoPos;
}

Related

How to get a 2D array of strings across the photon network in a Unity multi player game

I am trying to serialize a 2D array of strings to send over a network.
I have a couple ideas but I seem to be blocked by api or efficiency. I really don't want to serialize and send a small 2D array across a network 10 times a second when I only need it when I collide with something and ask for the information.
I have a list of items a player has in his cart. I want to make it okay to steal from that cart, so the other player has to be able to see what's in the cart.
If I use onphotonserializeview I thought I could convert the flatten the 2d array of strings into a 1D array of strings with a delimiter and stream.sendnext the delimited line and reconstitute on the other side, or some variation of that functionality.
public void serialize_merchandise_list() {
int width = 0;
int length = 0;
while((width < cart_list_width) && (length < cart_list_width)) {
width++;
if (width >= cart_list_width) {
length++;
width = 0;
}
// convert to bytes and then to string and append
System.Text.ASCIIEncoding.ASCII.GetBytes(merchandise_items[width, length]));
}
}
But doing that unnecessarily is an operation time nightmare, I want it on demand.
I was going to do a punrpc but I can't get a return value or ref parameter. What is the best approach here?
I want:
collide with cart
do you want to steal from cart --> yes --> show list
else --> go on your way
Afaik a one-dimensional array of strings would be no problem for Photon.
So I guess you could just flatten the array and additionally send the second size - lets name it element size (in contrary to the first one - the element count) as parameters.
Like e.g. lets say your array looks like
string[,] array2D = new string[4,2]{{"a", "b"}, {"c","d"}, {"e","f"}, {"g","h"}};
Then you would know the second (elementSize) dimension using either hardcoded or GetLength(int)
var elementSize = array2D.GetLength(1);
and you would simply flatten the array using
string[] arrayFlat = array2D.Cast<string>().ToArray();
So you would send these two informations via photon (I don't know photon in detail) but afaik you can do this one time without having to send it continiously. The two parameters would be
int elementSize, string[] arrayFlat
in this case with the values
2, string[8]{"a","b","c","d","e","f","g","h"}
So together:
public void SendArray2D()
{
int elementSize = array2D.GetLength(1);
string[] arrayFlat = array2D.Cast<string>().ToArray();
photonView.RPC(nameof(ReceiveArray2D), RpcTarget.All, elementSize, (object) arrayFlat);
}
Then on the receiver part you are getting
int elementSize = 2, string[] arrayFlat = string[8]{"a","b","c","d","e","f","g","h"}
and have to convert it back. You already know the second dimension elementSize = 2 so in order to get also the first one you simply do
var elementCount = arrayFlat.Length / elementSize; // = 4
so you know the 2D array you will have to fill would be
string[,] array2D = new string[elementCount, elementSize]; // = 4,2
and then you can simply iterate it and do something like
for (var x = 0; x < elementCount; x++)
{
for (int y = 0; y < elementSize; y++)
{
array2D[x, y] = arrayFlat[x * elementSize + y];
}
}
So together
[PunRpc]
public void ReceiveArray2D(int elementSize, string[] arrayFlat)
{
var elementCount = arrayFlat.Length / elementSize;
array2D = new string[elementCount, elementSize];
for (var x = 0; x < elementCount; x++)
{
for (int y = 0; y < elementSize; y++)
{
array2D[x, y] = arrayFlat[x * elementSize + y];
}
}
// Could also e.g. call some event like
OnReceivedArray2D?.Invoke (array2D);
}
public event Action<string[,]> OnReceivedArray2D;
So you could attach listeners to the event via
reference.OnReceivedArray2D += SomeHandler;
private void SomeHandler(string [,])
{
// ...
}
Or alternatively you could implement a class that stores your data in a flat array but lets you access it like if it would be a 2D array (in general a 2D array is anyway stored in memory as a flat one)
[Serializable]
public class SerializableArray2D
{
public readonly string[] ArrayFlat;
public readonly ElementSize;
public SerializableArray2D(int elementSize, string[] arrayFlat)
{
ElementSize = elementSize;
ArrayFlat = arrayFlat;
}
public SerializableArray2D(string[,] array2D) : this(array2D.GetLength(1), array2D.Cast<string>().ToArray()) { }
public SerializableArray2D(int elementSize, int elementCount) : this(elementSize, new string[elementCount]){}
public string this[int x, int y]
{
get { return ArrayFlat[x * ElementSize + y]; }
set { ArrayFlat[x * ElementSize + y] = value; }
}
}
usage would be e.g. Initialize it
var array2D = new string[4,2]{{"a", "b"}, {"c","d"}, {"e","f"}, {"g","h"}};
var serializableArray2D = new SerializableArray2D(array2D);
For accessing specific indices like in a 2D array
string example = serializableArray2D[1,1];
serializableArray2D[3,0] = "example";
For sending it
photonView.RPC(nameof(Receive), RpcTarget.All, serializableArray2D.ElementSize, (object)serializableArray2D.ArrayFlat);
And when receiving it
[PunRPC]
public void Receive(int elementSize, string[] arrayFlat)
{
serializableArray2D = new SerializableArray2D(elementSize, arrayFlat);
// Again e.g. call an event
OnReceivedSerializableArray2D?.Invoke(serializableArray2D);
}
public event Action<SerializableArray2D> OnReceivedSerializableArray2D;

How can a 2D array change value when the object it is stored in is never addressed?

I am coding chess, and have made a class called BoardObject to store board states, so I can have a list of them, making a history of the game. BoardObject has a field called boardValues, which is a 2D array which stores the values of each square on the board.
In my while loop where the game is played, if the user input passes my validity checks, the move they enter is passed into a method called movePieceTrad. During movePieceTrad, the list boardHistory is changed in some way to update with the move just made. Here's the problem: nowhere in movePieceTrad is boardHistory or any boardObject addressed. I have looked through with ctrl+f, every reference to boardHistory is in the main method.
In the code below, when I debug, lastInBoardHistory2 is different from what lastInBoardHistory1 was before movePieceTrad, but lastInBoardHistory1 also changes when I go through movePieceTrad, which makes no sense once again. What is going on?
lastInBoardHistory1 = boardHistory[boardHistory.Count - 1].getBoardValues();
movePieceTrad(arr[0], arr[1]);
lastInBoardHistory2 = boardHistory[boardHistory.Count - 1].getBoardValues();
Here is the code for the BoardObject class
namespace chess_v1
{
class BoardObject
{
private int[,] boardValues;
public int[,] possibleEnPassants;
public int[,] castlePiecesMoved;
public int turn = 0;
public BoardObject(int[,] squareValues, int[,] pep, int[,]castleInfo, int inputTurn)
{
boardValues = squareValues;
possibleEnPassants = pep;
castlePiecesMoved = castleInfo;
turn = inputTurn;
}
public int[,] getBoardValues()
{
return boardValues;
}
}
}
Alright, I've solved it.
When constructing a BoardObject, I passed in the input 2D arrays and simply set them equal to my field 2D arrays in BoardObject. Since 2D arrays are arrays of references to places in memory rather than self-contained arrays of arrays, this meant that ultimately I was simply passing along the references in my main method board to the fields in each BoardObject. So, when I moved a piece (changing values within the main method's board) the BoardObject, actually every BoardObject, also changed.
The fix is that instead of passing in the reference arrays in the constructor of BoardObject, I pass in the values with nested for loops. I have tested the functionality that was supposed to have worked before this issue, and everything is working great now!
This is the new BoardObject code; I didn't have to change anything outside of this:
namespace chess_v1
{
class BoardObject
{
public int[,] boardValues = new int[8,8];
public int[,] possibleEnPassants = new int[8,2];
public int[,] castlePiecesMoved = new int[2,3];
public int turn = 0;
public BoardObject(int[,] squareValues, int[,] pep, int[,]castleInfo, int inputTurn)
{
for (int i = 0; i < 8; i++)
{
for (int k = 0; k < 8; k++)
{
boardValues[i, k] = squareValues[i, k];
}
}
for (int i = 0; i < 8; i++)
{
for (int k = 0; k < 2; k++)
{
possibleEnPassants[i, k] = pep[i, k];
}
}
for (int i = 0; i < 2; i++)
{
for (int k = 0; k < 3; k++)
{
castlePiecesMoved[i, k] = castleInfo[i, k];
}
}
turn = inputTurn;
}
}
}

Getting the column totals in a 2D array but it always throws FormatException using C#

I am planning to get an array of the averages of each column.
But my app crashes at sum[j] += int.Parse(csvArray[i,j]); due to a FormatException. I have tried using Convert.ToDouble and Double.Parse but it still throws that exception.
The increments in the for loop start at 1 because Row 0 and Column 0 of the CSV array are strings (names and timestamps). For the divisor or total count of the fields that have values per column, I only count the fields that are not BLANK, hence the IF statement. I think I need help at handling the exception.
Below is the my existing for the method of getting the averages.
public void getColumnAverages(string filePath)
{
int col = colCount(filePath);
int row = rowCount(filePath);
string[,] csvArray = csvToArray(filePath);
int[] count = new int[col];
int[] sum = new int[col];
double[] average = new double[col];
for (int i = 1; i < row; i++)
{
for (int j = 1; j < col; j++)
{
if (csvArray[i,j] != " ")
{
sum[j] += int.Parse(csvArray[i,j]);
count[j]++;
}
}
}
for (int i = 0; i < average.Length; i++)
{
average[i] = (sum[i] + 0.0) / count[i];
}
foreach(double d in average)
{
System.Diagnostics.Debug.Write(d);
}
}
}
I have uploaded the CSV file that I use when I test the prototype. It has BLANK values on some columns. Was my existing IF statement unable to handle that case?
There are also entries like this 1.324556-e09due to the number of decimals I think. I guess I have to trim it in the csvToArray(filePath) method or are there other efficient ways? Thanks a million!
So there are a few problems with your code. The main reason for your format exception is that after looking at your CSV file your numbers are surrounded by quotes. Now I can't see from your code exactly how you convert your CSV file to an array but I'm guessing that you don't clear these out - I didn't when I first ran with your CSV and experienced the exact same error.
I then ran into an error because some of the values in your CSV are decimal, so the datatype int can't be used. I'm assuming that you still want the averages of these columns so in my slightly revised verion of your method I change the arrays used to be of type double.
AS #musefan suggested, I have also changed the check for empty places to use the IsNullOrWhiteSpace method.
Finally when you output your results you receive a NaN for the first value in the averages column, this is because when you don't take into account that you never populate the first position of your arrays so as not to process the string values. I'm unsure how you'd best like to correct this behaviour as I'm not sure of the intended purpose - this might be okay - so I've not made any changes to this for the moment, pop a mention in the comments if you want help on how to sort this!
So here is the updated method:
public static void getColumnAverages(string filePath)
{
// Differs from the current implementation, reads a file in as text and
// splits by a defined delim into an array
var filePaths = #"C:\test.csv";
var csvArray = File.ReadLines(filePaths).Select(x => x.Split(',')).ToArray();
// Differs from the current implementation
var col = csvArray[0].Length;
var row = csvArray.Length;
// Update variables to use doubles
double[] count = new double[col];
double[] sum = new double[col];
double[] average = new double[col];
Console.WriteLine("Started");
for (int i = 1; i < row; i++)
{
for (int j = 1; j < col; j++)
{
// Remove the quotes from your array
var current = csvArray[i][j].Replace("\"", "");
// Added the Method IsNullOrWhiteSpace
if (!string.IsNullOrWhiteSpace(current))
{
// Parse as double not int to account for dec. values
sum[j] += double.Parse(current);
count[j]++;
}
}
}
for (int i = 0; i < average.Length; i++)
{
average[i] = (sum[i] + 0.0) / count[i];
}
foreach (double d in average)
{
System.Diagnostics.Debug.Write(d + "\n");
}
}

C# three dimensional array, convert row to array

var examples = new double[1000][][];
for (int i = 0; i < 1000; i++)
{
examples[i]= new double[2][]; //the Set
examples[i][0] = new double[] { x(i), y(i) }; //the Inputs
examples[i][1] = new double[] { Math.Sin(x(i) * y(i)), Math.Sin(x(i) / y(i)) }; //the Target
}
x(i) means x depend on i
And I need to collect the inputs like that examples[][0] = new double[1000][]
because It will consume more memory to create a new array like that
for (int i = 0; i < 1000; i++)
{
input[i][0]=x(i);
input[i][1]=y(i);
}
My first thought would be to reconsider the design decision that ended up with a [1000][2][2] array which you want to pull a flattened [1000][2] array out of by taking a specific center-array value...
As far as accessing it without re-allocating memory, you're not going to get it as an array without using more memory sorry, but what you could do is get an IEnumerable<double[]> which may suffice depending on your purposes by using yield (Which will make it evaluate each result individually as you enumerate over it).
EG:
public IEnumerable<double[]> GetResults()
{
for (int i = 0; i < 1000; x++)
{
yield return examples[i][0];
}
}
How useful that is will depend on how you plan to use the results, but you won't get a new array without using more memory.

How to access an object instance which is inside an object array?

I am trying to access an object which is a member of an object array, is that possible ?
I have declared a structure named Particle, and initialized an object array of "Particle" about 40 particles,now I need to access each particle, for ex: particle.Gbest
any one can help ??
here is my code:
struct particle
{
double[] position = new double[100];
double Gbest, Lbest;
double Pconst = 0.5;
}
object[] swarm = new object[swarm_size];
for (int i = 0; i < swarm_size; i++)
{
swarm[i] = new particle();
}
This code is invalid to start with:
struct particle
{
double[] position = new double[100];
}
You can't specify variable initializers for instance variables in structs.
However, accessing data within another object or value is easy - if it's accessible. In this case your fields are private and you haven't provided any access methods or properties, so you won't be able to get at them "from the outside" without more code.
Here's some modified code:
public class Particle
{
private readonly double[] positions = new double[100];
// TODO: Rename these to something useful
public double Gbest { get; private set; }
private double Lbest;
private double Pconst = 0.5;
public Particle(int g)
{
Gbest = g; // Or whatever
}
}
List<Particle> swarm = new List<Particle>();
for (int i = 0; i < swarmSize; i++)
{
swarm.Add(new Particle(i));
}
double total = 0;
foreach (Particle particle in swarm)
{
total += particle.Gbest;
}
Now this isn't doing anything particularly useful, because it's not clear what you're trying to do - but I would suggest you get an introductory book on C#. Stack Overflow is great for specific questions, but I think you're early enough on your journey into C# that a good book or tutorial would help you more.
var swarm = new particle[swarm_size];
for (int i = 0; i < swarm_size; i++)
{
swarm[i] = new particle();
}
To access properties of the array you could walk it like this:
for (int i = 0; i < swarm_size; i++)
{
Console.WriteLine(swarm[i].Gbest);
Console.WriteLine(swarm[i].Lbest);
}
EDIT: swarm declaration was incorrect.
If you know the index of the particle, you can simply use:
particle part = (particle)swarm[i];
// do stuff with part
If you don't know the index, you can iterate over them:
foreach( particle part in swam )
{
// do stuff with part
}
Or you can use Linq-to-Objects to do more sophisticated stuff, but I think you need to start with the simple stuff...
By the way, if you can, declare swarm as:
particle[] swarm = new particle[swarm_size];
and get the benefit of type-safety.
struct particle
{
public double[] position = new double[100];
public double Gbest, Lbest;
public double Pconst = 0.5;
}
particle[] swarm = new particle[swarm_size];
for (int i = 0; i < swarm_size; i++)
{
swarm[i] = new particle();
}
foreach(particle p in swarm)
{
// do magic here
}
You can either change your array type to Particle and access it with index like...
particle[] swarm = new particle[swarm_size];
particle firstParticle = swarm[0];
or you can cast the object back to a particle...
particle firstParticle = (particle)swarm[0];
I would recommend the first option thou for performance reasons.

Categories