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.
Related
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;
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;
}
(If you can think of a better title, please let me know.)
I’m working on a route optimization program. I'm starting with a list of points which the route needs to include. My first step is to create a list of all possible routes (permutations). I then remove any route I can (for example, if one stop must precede another). Once that's done I calculate the distance and time between each point, in each possible route. Each point is an object (TPoint) and all the distance and time values are stored in a separate class called TData, which is stored in each instance of TPoint. My problem is this: when I try to update the TData in, say, the first stop, in the first possible route it will update the TData for that same TPoint in each possible route. This is because the class is a reference type and is stored on the heap. I’m looking for a solution that allows me to store the TData on each TPoint.
Here's some example code (the following code demonstrates how when I modify one object (TPoint), I'm only actually using the reference to modify the object on the heap):
Main
// Let's create a list of points we need to hit.
List<TPoint> lstInitial = new List<TPoint>();
lstInitial.Add(new TPoint("A", new TData(-1, -1)));
lstInitial.Add(new TPoint("B", new TData(-1, -1)));
lstInitial.Add(new TPoint("C", new TData(-1, -1)));
// Now let's get all possible routes
IList<IList<TPoint>> lstPermutations = Permutations(lstInitial);
// Let's write these values to the first point, in the first possible route.
lstPermutations[0][0].oTData.distance = 10;
lstPermutations[0][0].oTData.minutes = 20;
foreach (IList<TPoint> perm in lstPermutations)
{
foreach (TPoint p in perm)
{
Response.Write(p.id + "|" + p.oTData.distance + "|" + p.oTData.minutes);
Response.Write(" ");
}
Response.Write("<br />");
}
Permutation Function
// Get permutations
private static IList<IList<T>> Permutations<T>(IList<T> list)
{
List<IList<T>> perms = new List<IList<T>>();
// If the list is empty, return an empty list.
if (list.Count == 0)
{
return perms;
}
// This is a loop method to get the factorial of an integer
int factorial = 1;
for (int i = 2; i <= list.Count; i++)
{
// shortcut for: factorial = factorial * i;
factorial *= i;
}
for (int v = 0; v < factorial; v++)
{
//List<T> s = new List<T>(list);
List<T> s = new List<T>(list);
int k = v;
for (int j = 2; j <= list.Count; j++)
{
int other = (k % j);
T temp = s[j - 1];
s[j - 1] = s[other];
s[other] = temp;
k = k / j;
}
perms.Add(s);
}
return perms;
}
Classes
public class TPoint
{
public TPoint(string _id, TData _oTData)
{
id = _id;
oTData = _oTData;
}
public string id { get; set; }
public int someInt { get; set; }
public TData oTData { get; set; }
}
public class TData
{
public TData(int _distance, int _minutes)
{
distance = _distance;
minutes = _minutes;
}
public int distance { get; set; }
public int minutes { get; set; }
}
It kind of seems as if I've managed to paint myself into a corner. I can think of a few solutions, but they seem messy so I figured I'd ask the experts on this one.
Edit
Can anyone think of why this wouldn't be a good idea?
Instead of this, which modifies the object on the heap (and affects every point in each possible route):
lstPermutations[0][0].oTData.distance = 10;
lstPermutations[0][0].oTData.minutes = 20;
Use this, which just creates a new instance of the class:
TPoint oTPoint = new TPoint(lstPermutations[0][0].id, new TData(10, 20));
lstPermutations[0][0] = oTPoint;
If you make TData a struct then it will be copied by value and not by reference. Otherwise you'll have to make a shallow clone which copies values.
Why not make your simple TData type immutable by removing the set accessors, so that it won't matter much if it is copied by value or copied by reference. It could be functionally equivalent to Tuple<int, int>.
Whether the object is stored on the heap or somewhere else is probably unimportant. If you decide to make the object immutable, it will be natural to make it a struct, though, but a class is also fine.
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.
I have this struct:
struct Map
{
public int Size;
public Map ( int size )
{
this.Size = size;
}
public override string ToString ( )
{
return String.Format ( "Size: {0}", this.Size );
}
}
When using array, it works:
Map [ ] arr = new Map [ 4 ] {
new Map(10),
new Map(20),
new Map(30),
new Map(40)};
arr [ 2 ].Size = 0;
But when using List, it doesn't compile:
List<Map> list = new List<Map> ( ) {
new Map(10),
new Map(20),
new Map(30),
new Map(40)};
list [ 2 ].Size = 0;
Why?
The C# compiler will give you the following error:
Cannot modify the return value of 'System.Collections.Generic.List.this[int]' because it is not a variable
The reason is that structs are value types so when you access a list element you will in fact access an intermediate copy of the element which has been returned by the indexer of the list.
From MSDN:
Error Message
Cannot modify the return value of
'expression' because it is not a
variable
An attempt was made to modify a value
type that was the result of an
intermediate expression. Because the
value is not persisted, the value will
be unchanged.
To resolve this error, store the
result of the expression in an
intermediate value, or use a reference
type for the intermediate expression.
Solutions:
Use an array. This gives you direct access to the elements (you are not accessing a copy)
When you make Map a class you can still use a List to store your element. You will then get a reference to a Map object instead of an intermediate copy and you will be able to modify the object.
If you cannot change Map from struct to a class you must save the list item in a temporary variable:
List<Map> list = new List<Map>() {
new Map(10),
new Map(20),
new Map(30),
new Map(40)
};
Map map = list[2];
map.Size = 42;
list[2] = map;
Because it is a struct, when using the List<T>, you're are creating copies.
When using a struct, it is better to make them immutable. This will avoids effects like this.
When using an array, you have direct access to the memory structures. Using the List<T>.get_Item you work on a return value, that is, a copy of the structure.
If it was a class, you would get a copy of a pointer to the class, but you would not notice this, since pointers are hidden in C#.
Also using the List<T>.ToArray does not solve it, because it will create a copy of the internal array, and return this.
And this is not the only place where you will get effects like this when using a struct.
The solution provided by Divo is a very good workaround. But you have to remember to work this way, not only when using the List<T> but everywhere you want to change a field inside the struct.
I'm not an XNA developer, so I cannot comment on how strict is the requirement to use structs vs. classes for XNA. But this does seem to be a much more natural place to use a class in order to get the pass-by-ref semantics you are looking for.
One thought I had is that you could make use of boxing. By creating an interface, say, 'IMap' in your case, to be implanted by your 'Map' struct, and then using a List<IMap>, the list will be holding System.Object objects, which are passed by reference. For example:
interface IMap
{
int Size { get; set; }
}
struct Map: IMap
{
public Map(int size)
{
_size = size;
}
private int _size;
public int Size
{
get { return _size; }
set { _size = value; }
}
public override string ToString()
{
return String.Format("Size: {0}", this.Size);
}
}
Which could then be called by the following:
List<IMap> list = new List<IMap>() {
new Map(10),
new Map(20),
new Map(30),
new Map(40)};
list[2].Size = 4;
Console.WriteLine("list[2].Size = " + list[2].Size.ToString());
Note that these structs would only be boxed once, when passed into the List in the first place, and NOT when called using code such as 'list[2].Size = 4', so it should be fairly efficient, unless you are taking these IMap objects and casting back to Map (copying it out of the List<IMap>) in other parts of your code.
Although this would achieve your goal of having direct read-write access to the structs within the List<>, boxing the struct is really stuffing the struct into a class (a System.Object) and I would, therefore, think that it might make more sense to make your 'Map' a class in the first place?
Mike
I keep coming back to this question when trying to calculate normals on a vertex buffer in XNA.
The best XNA solution I came up with was to copy the data (or store it) in an array.
private void SomeFunction()
{
List<VertexBasicTerrain> vertexList = GenerateVertices();
short[] indexArray = GenerateIndices();
CalculateNormals(vertexList, ref indexArray); // Will not work
var vertexArray = vertexList.ToArray();
CalculateNormals(ref vertexArray, ref indexArray);
}
// This works (algorithm from Reimers.net)
private void CalculateNormals(ref VertexBasicTerrain[] vertices, ref short[] indices)
{
for (int i = 0; i < vertices.Length; i++)
vertices[i].Normal = new Vector3(0, 0, 0);
for (int i = 0; i < indices.Length / 3; i++)
{
Vector3 firstvec = vertices[indices[i * 3 + 1]].Position - vertices[indices[i * 3]].Position;
Vector3 secondvec = vertices[indices[i * 3]].Position - vertices[indices[i * 3 + 2]].Position;
Vector3 normal = Vector3.Cross(firstvec, secondvec);
normal.Normalize();
vertices[indices[i * 3]].Normal += normal;
vertices[indices[i * 3 + 1]].Normal += normal;
vertices[indices[i * 3 + 2]].Normal += normal;
}
for (int i = 0; i < vertices.Length; i++)
vertices[i].Normal.Normalize();
}
// This does NOT work and throws a compiler error because of the List<T>
private void CalculateNormals(List<VertexBasicTerrain> vertices, ref short[] indices)
{
for (int i = 0; i < vertices.Length; i++)
vertices[i].Normal = new Vector3(0, 0, 0);
for (int i = 0; i < indices.Length / 3; i++)
{
Vector3 firstvec = vertices[indices[i * 3 + 1]].Position - vertices[indices[i * 3]].Position;
Vector3 secondvec = vertices[indices[i * 3]].Position - vertices[indices[i * 3 + 2]].Position;
Vector3 normal = Vector3.Cross(firstvec, secondvec);
normal.Normalize();
vertices[indices[i * 3]].Normal += normal;
vertices[indices[i * 3 + 1]].Normal += normal;
vertices[indices[i * 3 + 2]].Normal += normal;
}
for (int i = 0; i < vertices.Length; i++)
vertices[i].Normal.Normalize();
}
list [ 2 ].Size = 0;
is in fact:
//Copy of object
Map map = list[2];
map.Size = 2;
Use class in place of struct.
I decided to directly replace the result on a copy and reassign the result like:
Map map = arr [ 2 ];
map.Size = 0;
arr [ 2 ] = map;