I have list of structure. I want to modify a particular data from the structure.
And the structure is at the particular index location of the List.
I want to do something like this:
struct sample
{
int a;
string name;
}
List<sample> list = new List<sample>();
for(int i=0; i < list.Count; i++)
{
list[i].a = someotherlist[i].data;
}
The problem is that the list indexer creates a copy of the struct, i.e. it is really:
for(int i=0; i < list.Count; i++)
{
var completelyIsolatedClone = list[i];
completelyIsolatedClone.a = someotherlist[i].data;
}
The compiler is preventing you making an obvious mistake. The code you have uses the get, mutates a separate copy of the data, but never puts it back - so your change doesn't do anything useful. Note that the Mono folks think it would be nice if it worked your way, though: http://tirania.org/blog/archive/2012/Apr-11.html
Note that an array works differently; with an array you are touching the struct in place, so the following would work fine:
for(int i=0; i < list.Count; i++)
{
someArray[i].a = someotherlist[i].data;
}
Another approach is to copy the data out (the get accessor), mutate it, and put it back:
for(int i=0; i < list.Count; i++)
{
var completelyIsolatedClone = list[i];
completelyIsolatedClone.a = someotherlist[i].data;
list[i] = completelyIsolatedClone;
}
or better, acoid mutable structs completely, perhaps with a method that applies the change to a new copy:
for(int i=0; i < list.Count; i++)
{
list[i] = list[i].SetA(someotherlist[i].data);
}
where SetA creates a new struct, like DateTime.AddDays etc, i.e.
public SomeType SetA(int a) {
return new SomeType(this.X, this.Y, a, this.Z);
}
The reason you can't do it is because Sample is a struct, if you change it to a class then you can modify it. Structures are passed by value, that is, when a structure is returned by a method, a copy of the structure is returned, not the orginal structure. So when list[i].a = someotherlist[i].data; is run, you are actually modifying the copy and the orginal structure is not being changed. The compilers prevents you from doing this as it is probably not what you had intended.
You may look at this thread Why couldnot I modify the value of item from Generic Collections) ?
I just modified my code as bellow and it works fine for me
public struct test
{
public int data;
public string name;
public int port_index;
}
static void Main(string[] args)
{
List<test> look_up = new List<test>();
test obj;
obj.data = 1;
obj.port_index = 0;
obj.name = "aaaa";
look_up.Add(obj);
test obj1;
obj1.data=3;
obj1.port_index=1;
obj1.name="sssss";
look_up.Add(obj1);
for(int i=0;i<look_up.Count;i++)
{
if (i == 1)
{
test temp = look_up[i];
temp.data = 5;
look_up[i] = temp;
}
}
}
Related
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;
}
}
}
I would like to store reference of an ushort variable in an ushort array, so that the value of the variable changes when I change the values inside the ushort array. Here is my sample code which will give a clear picture of what I'm trying to achieve.
public void IndexSetter(List<int> indexVal,Rootobject objectVal)
{
ushort[] refereneArray = new ushort[8]
{
objectVal.index1, objectVal.index2,
objectVal.index3 , objectVal.index4,
objectVal.index5, objectVal.index6,
objectVal.index7, objectVal.index8
};
for(int j = 0; j< indexVal.Count;j++)
{
refereneArray[j] =(ushort) indexVal[j];
}
}
Instead of storing the values like from above code , I need to store the reference so that the changes in indexVal list reflect in the values of index1, index2.. etc
I´d suggest not to have 8 indexes with the exact same name (except a number). Give every member of your class a name describing what it´s ment to be, however index6 isn´t really self-explanatory.
Having said this what you can do is to have one array of indexes within your class itself:
class Rootobject
{
public int[] Indexes { get; set; }
}
Now you can access them as follows:
public void IndexSetter(List<int> indexVal, Rootobject objectVal)
{
for(int i = 0; i < indexVal.Count; i++)
objectVal.Indexes[index] = indexVal[i];
}
Or even shorter:
objectVal.Indexes = indexVal.Cast<ushort>().ToArray();
You can do it with unsafe code, using array of pointers like this:
static unsafe void IndexSetter(IList<ushort> indexVal, Rootobject objectVal) {
fixed (ushort* r1 = &objectVal.index1)
fixed (ushort* r2 = &objectVal.index2) {
ushort*[] refereneArray = {r1, r2};
for (int j = 0; j < indexVal.Count; j++) {
*refereneArray[j] = (ushort) indexVal[j];
}
}
}
Should you really do this in real application is another story. There is very high chance that there is a better way to solve your problem, but you didn't tell us what the actual problem is.
If perfomance is not critical - you can use reflection:
static void IndexSetter2(IList<ushort> indexVal, Rootobject objectVal) {
int i = 0;
foreach (var field in objectVal.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(c => c.Name.StartsWith("index") && c.FieldType == typeof(ushort))
.OrderBy(c => c.Name)) {
field.SetValue(objectVal, indexVal[i]);
i++;
}
}
(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.
I am using the following code in C#. I am adding the values into the arraylist by using index. Now I want to read the values from the arraylist by using the index only. In the following example I am simply reading all the values from the arrylist but I want to read the values from the arrylist based on index( for e.g Customer_Details[i]) for each element at index i.
public struct Cust_Info
{
public String Client_Key;
public String Registration_Key;
public int Standard;
public Cust_Info(String C_Key, String Reg_Key, int Std)
{
Client_Key = C_Key;
Registration_Key = Reg_Key;
Standard = Std;
}
}
private void Form1_Load(object sender, EventArgs e)
{
ArrayList Customer_Details = new ArrayList();
for (int i = 0; i < 1; i++)
{
Customer_Details.Insert(i, new Cust_Info("A", "B", 1));
}
//for (int i = 0; i < 1; i++)
//{
Customer_Details.Insert(1, new Cust_Info("C", "D", 2));
for (int i = 0; i < 1; i++)
{
ArrayList obj=new ArrayList();
//((ArrayListOFStructures.Form1.Cust_Info)((new System.Collections.ArrayList.ArrayListDebugView(Customer_Details)).Items[0])).Client_Key
//obj = (ArrayList)Customer_Details[i];
foreach (Cust_Info temp in Customer_Details)
{
//comboBox1.Items.Add(Customer_Details[0].ToString());
comboBox1.Items.Add(temp.Client_Key);
comboBox1.Items.Add(temp.Registration_Key);
comboBox1.Items.Add(temp.Standard);
}
}
}
In the above code i want to make the use the structure only. How can I read the values from the arrylist based on index. Can you please provide me any code or link through which I can resolve the above issue ?
I'm confused; you can get an item out of an ArrayList by index simply by:
Cust_Info cust = (CustInfo)theList[index];
However, ArrayList is pretty rare in anything >= .NET 2.0, a List<Cust_Info> would make this much easier. Also, Cust_Info looks to me very much like it should be a class (it is very rare to write a struct in .NET, and usually to denote "values" - a customer isn't a "value"). And public fields are also very much discouraged.
Note that currently you are (because it is a struct) actually copying the Cust_Info whenever you fetch it from (or place it in) the list; that isn't necessarily what you intend...
You can try something like
ArrayList arr = new ArrayList();
for (int iIndex = 0; iIndex < arr.Count; iIndex++)
{
object o = arr[iIndex];
}
But I would rather go with
List Class and List.Count Property
for(int i=0; i<Customer_Details.Count/*or.Length*/; i++)
Customer_Details[i] = something;
What is the slickest way to initialize an array of dynamic size in C# that you know of?
This is the best I could come up with
private bool[] GetPageNumbersToLink(IPagedResult result)
{
if (result.TotalPages <= 9)
return new bool[result.TotalPages + 1].Select(b => true).ToArray();
...
If by 'slickest' you mean fastest, I'm afraid that Enumerable.Repeat may be 20x slower than a for loop.
See http://dotnetperls.com/initialize-array:
Initialize with for loop: 85 ms [much faster]
Initialize with Enumerable.Repeat: 1645 ms
So use Dotnetguy's SetAllValues() method.
use Enumerable.Repeat
Enumerable.Repeat(true, result.TotalPages + 1).ToArray()
EDIT: as a commenter pointed out, my original implementation didn't work. This version works but is rather un-slick being based around a for loop.
If you're willing to create an extension method, you could try this
public static T[] SetAllValues<T>(this T[] array, T value) where T : struct
{
for (int i = 0; i < array.Length; i++)
array[i] = value;
return array;
}
and then invoke it like this
bool[] tenTrueBoolsInAnArray = new bool[10].SetAllValues(true);
As an alternative, if you're happy with having a class hanging around, you could try something like this
public static class ArrayOf<T>
{
public static T[] Create(int size, T initialValue)
{
T[] array = (T[])Array.CreateInstance(typeof(T), size);
for (int i = 0; i < array.Length; i++)
array[i] = initialValue;
return array;
}
}
which you can invoke like
bool[] tenTrueBoolsInAnArray = ArrayOf<bool>.Create(10, true);
Not sure which I prefer, although I do lurv extension methods lots and lots in general.
I would actually suggest this:
return Enumerable.Range(0, count).Select(x => true).ToArray();
This way you only allocate one array. This is essentially a more concise way to express:
var array = new bool[count];
for(var i = 0; i < count; i++) {
array[i] = true;
}
return array;
Many times you'd want to initialize different cells with different values:
public static void Init<T>(this T[] arr, Func<int, T> factory)
{
for (int i = 0; i < arr.Length; i++)
{
arr[i] = factory(i);
}
}
Or in the factory flavor:
public static T[] GenerateInitializedArray<T>(int size, Func<int, T> factory)
{
var arr = new T[size];
for (int i = 0; i < arr.Length; i++)
{
arr[i] = factory(i);
}
return arr;
}
Untested, but could you just do this?
return result.Select(p => true).ToArray();
Skipping the "new bool[]" part?