I'm coming from a Python background and am dealing with code that creates many variables with the same name + an integer attached to the end, and need to replicate Python's f'something here {variable}' method in C#. How can I do this?
i.e.
int num1 = 1;
int num2 = 2;
int num3 = 3;
int num4 = 4;
etc...
is there a way to do something like
for (int i=1;i<5;i++)
{
int f'num{i}' = i;
}
In an ideal world, you never number variables and just use an array (or some other collection). So you would have:
for (int i=0;i<5;i++)
{
num[i] = i;
}
Which requires your list of variables to be instead one variable that is indexable (like an array)
int[] num = new int[5];
The only way to access a variable in C# from a string is with reflection (which is a fairly advanced concept, easy to get wrong, and not very efficient). That being said, you'd do something like:
Type thisClass = this.GetType(); //Even better, typeof(WhateverClassThisIs);
for (int i=1;i<5;i++)
{
FieldInfo field = thisClass.GetField($"num{i}");
field.SetValue(this, i);
}
Note that this only works if num1 etc. are existing class members (it does not create them) and not local to the function. If you have local variables, you are basically out of luck.
Related
I am trying to store each iteration of an array as it is being sorted through. For some reason the jagged array I return just becomes an array of the final sorted array. My code is below I cannot figure out why any help would be really appreciated. Thanks.
namespace SortingUI.Utils
{
public class Sorting
{
public static int[][] SortInt(int[] originalArray)
{
int length = originalArray.Length;
int tempVal, smallest;
int[][] iterations = new int[length-1][];
for (int i = 0; i < length - 1; i++)
{
smallest = i;
for (int j = i + 1; j < length; j++)
{
if (originalArray[j] < originalArray[smallest])
{
smallest = j;
}
}
tempVal = originalArray[smallest];
originalArray[smallest] = originalArray[i];
originalArray[i] = tempVal;
iterations[i] = originalArray;
}
return iterations;
}
}
}
If i understand your problem, the reason you are getting the same values (and not a snapshot) is because you are storing a reference to the array, and not a copy of the values themselves.
Arrays are reference types, so when you assign them to another variable you are only copying reference and not the contents. If you change the contents, all the references will reflect that
You can make use of Array.Copy to copy the values at the point in time from the originalArray
...
var tempVal = originalArray[smallest];
originalArray[smallest] = originalArray[i];
originalArray[i] = tempVal;
// Create some new memory
iterations[i] = new int[originalArray.Length];
// Copy the contents
Array.Copy(originalArray, iterations[i], originalArray.Length);
Note this is totally untested and i have no idea if the rest of your code is working as intended
Additional Resources
Array.Copy Method
Copies a range of elements in one Array to another Array and performs
type casting and boxing as required.
Arrays (C# Programming Guide)
Array types are reference types derived from the abstract base type Array. Since this type implements IEnumerable and IEnumerable,
you can use foreach iteration on all arrays in C#.
I have this script in PHP where I use
while( in_array(array('x' => $x, 'y' => $y), $worldMap) ){ ... }
to check if my worldMap already have a room at those XY positions.
IF TRUE I randomize either X or Y and the WHILE loop check again with the new values and so on, IF FALSE I populate the worldMap array with last XY generated.
Now, I'm trying to rewrite that code in C# but I'm getting an infinite Loop.
Here's my current Code:
public int nbRooms = 10;
private Dictionary<int, Dictionary<string, int>> worldMap = new Dictionary<int, Dictionary<string, int>>();
private Dictionary<string, int> roomXY = new Dictionary<string, int>();
private string[] arrayXY = {"X","Y"};
private int[] arrayNbr = {-1,1};
private int X = 0;
private int Y = 0;
for(int i = 0; i <= nbRooms; i++)
{
while(worldMap.ContainsValue(roomXY))
{
string XorY = arrayXY[Random.Range(0, 2)];
switch(XorY)
{
case "X": X += arrayNbr[Random.Range(0, 2)];
break;
case "Y": Y += arrayNbr[Random.Range(0, 2)];
break;
}
roomXY.Clear();
roomXY.Add("X", X);
roomXY.Add("Y", Y);
}
worldMap.Add(i, roomXY);
}
The basic issue here is that, by default, a comparison between two reference type objects simply compares the reference itself. While you change the contents of the roomXY object, you do not change the reference itself (i.e. the actual object remains the same), and so once you have added the object to your worldMap dictionary once, it is always there when you check the next time through the loop.
A very good illustration of why when porting code it's important to port the intent but not necessarily the exact implementation, due to differences in the way the language handles things.
In fact, based on the code you've posted, it seems as though you probably don't want to use a dictionary class anywhere in this case. It can be made to work using dictionary objects, but you aren't really taking advantage of the dictionary-like nature of those data structures. It seems like you are using dictionaries here more because semantically they seem to operate similarly to the data structures you were using in PHP, but in fact C# offers other language features that would probably be more appropriate.
For example, you could have written your code like this:
struct Room
{
public readonly int X;
public readonly int Y;
public Room(int x, int y) { X = x; Y = y; }
}
public int nbRooms = 10;
private Room[] worldMap = new Room[nbRooms];
private string[] arrayXY = {"X","Y"};
private int[] arrayNbr = {-1,1};
private int X = 0;
private int Y = 0;
private Room roomXY = new Room(X, Y);
for(int i = 0; i <= nbRooms; i++)
{
while(Array.IndexOf(worldMap, roomXY) >= 0)
{
string XorY = arrayXY[Random.Range(0, 2)];
switch(XorY)
{
case "X": X += arrayNbr[Random.Range(0, 2)];
break;
case "Y": Y += arrayNbr[Random.Range(0, 2)];
break;
}
roomXY = new Room(X, Y);
}
worldMap[i] = roomXY;
}
Because of the way C# implements equality comparisons by default for value types (i.e. a struct), this will compare the actual contents of the roomXY value against the values found in worldMap.
Note: both your original implementation and the one above use a linear search in the worldMap data structure. For the small number of rooms here (10), this should be fine. But you should be aware that this can be very inefficient for larger sets of data. You will likely want to use a different approach to generate this data in that case (e.g. hash set, flags in a larger map data structure, shuffling, etc.).
ContainsValue uses the default equality comparer EqualityComparer.Default for TValue, the type of values in the dictionary. roomXY is a (reference to) dictionary object, the reference is not changing by changing the X and Y coordinates of this object so you run into an infinite while loop.
I have rewritten this question because not everyone understood. Hope it's ok, it's the same main problem.Very sorry
I have a winform with 15 progress bars called: "baraClasa1", "baraClasa2", "baraClasa3" ... "baraClasa15". I have to assign the .VALUE property (as in int) to all of them, from some database records. (The records access the different values from different time periods)
I was thinking that maybe it is possible to use a loop to assign the .Value property to all of them by doing something like:
for(int i=0; i<value; i++)
{
"baraClasa+i".Value = 20 + i;
}
Is it possible to compose the name of the variables like that?
I don't know much about dictionaries, lists but looking into. If nothing works il just do the ugly:
int value = 20;
baraClasa1 = value;
baraClasa2 = value +1;....
Thank you for all help
You have to do a little reflection.
public string variable0, variable1, variable2, variable3, variable4, variable5;
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 6; i++)
{
//pretending my variable names are variable1, variable2.. ("variable" is NOT an array! just the "assign" variable)
System.Reflection.FieldInfo info = this.GetType().GetField("variable" + i.ToString());
// replace "testing" with the value you want e.g. assign[i]
info.SetValue(this, "testing");
}
// Do something with your new values
}
No need to use reflection with the updated question. The control collection has a built in find for getting a control by the name string.
for (int i = 0; i < 6; i++)
{
ProgressBar bar = (ProgressBar)this.Controls["baraClasa" + i.ToString()];
bar.Value = 50;
}
This is a design problem. Create a collection for items with common use (like progress bars for that matter) and iterate over the collection to perform actions on them.
If these are prorgress bars you might want to use an event-driven design (another link) to update their progress, meaning that each time a bar has made some progress, the event for the progress will send an update only to that bar, and not iterate over the entire list.
You may want to read an introduction to event driven programming in C# before re-factoring your code.
It really isn't possible in C# to refer to local variables in a dynamic fashion as you are trying to do. Instead what you would do in C# is store the value in a dictionary where the key can be generated in a dynamic fashion.
For example let's say all of your variable1, variable2, ... variableN were of type int. Instead of
int variable1 = 0;
int variable2 = 0;
...
int variableN = 0;
You would instead do the following
Dictionary<string, int> map = new Dictionary<string, int>();
for (int i = 0; i < N; i++) {
map[i.ToString()] = 0;
}
If the values are a of a fixed number and always linear in progress it may make sense to use an array instead of a dictionary
int[] array = new int[N];
for (int i = 0; i < N; i++) {
array[i] = 0;
}
You can't do it that way. You need an array. Every time you notice yourself having a variable2, you need an array. You may not know it yet, but you do.
No, you can't do it in C#, it's syntactically impossible. But if you want access form controls which has different names like this you can do the following:
for(int i=0; i<20; i++)
{
var name = "variable" + i;
this.Controls[name].Text = "etc..." // here you can access your control
}
If you want to have names for your objects, use a dictionary:
Dictionary<string, type> myDict = new Dictionary<string, type>()
string naming = "MyPattern{0}";
for (int i = 0; i <value; i++) {
myDict.add(string.Format(naming, i.ToString()), assign[i]);
}
And then you can access them by doing, for example:
myDict["MyPattern1"]
However, I suggest you would be better off using a collection like a List or array.
Arrays, lists, dictionaries, hash maps... collections in general are what you would use here. For example, if you have a dictionary, then it consists of key/value pairs. So a dictionary might look like this:
var variable = new Dictionary<int, string>();
Where the int is the key for any given entry, and the string is the value. You'd assign values in something like this:
for(int i = 0; i < value; i++)
variable.Add(i, assign[i]);
Of course, since i is just an incrementing integer in this case (unless you have some other key in mind?), then it works just as well as an indexer on a list. Something like this:
var variable = new List<string>();
for (int i = 0; i < value; i++)
variable.Add(assign[i]);
In both cases, you'd access the assigned value later by referencing its key (in a dictionary) or its index (in a list, or any array):
var someOtherVariable = variable[x];
Where x is an integer value present in the dictionary's keys or in the array's size.
If you can put names of all variables in an array such as 'variable', and they are unique, you can try to use dictionary :
Dictionary<object, object> dictionary = new Dictionary<string, object>();
for(int i=0; i<value; i++)
{
dictionary.Add(variable[i], assign[i]);
}
Since I couldn't explain very good in my last question and I didn't get an answer that could satisfy me, I decided to open a new one. Straight to the point, what I'm basically trying to do is compiling a variable (the value it holds) as a part of code (and specificly in my case referencing another variable)
Say I have:
int var_1, var_2, var_3 ... var_10;
for (int i = 1; i <= 10; i++)
{
var_%i%=20; //if i is 1, then var_1's value will be set to 20, if i is 2, then var_2's value will be set to 20. So basically this loop sets the value of var_1 .. var_10 to 20
}
I can explain in an even simpler way, if in any case the latter is not clear.
int var_5;
int SomeOtherVar = 5;
var_%SomeOtherVar% = 10; // so var_5 (where 5 is the value of SomeOtherVar) is set to 10
Is this doable and if it is, what's the approach?
No you can't do that, why dont you use an array?
int[] array = new int[3];
for (int i = 0; i < array.Length; ++i)
{
array[i] = 20;
}
Hope it helps.
It's not doable. Use an array instead. The type is int[] but I suggest you go read a tutorial about arrays to understand how to create and use them.
I can't think of a situation where you'd need to do this. If you wish to store values against a consecutive list of numbers, use an array. Otherwise you could use a Dictionary. For example to store "var1" = 20, "var2" = 20 as in your question, you could do this:
Dictionary<string, int> dict = new Dictionary<string, int>();
for (int i = 1; i <= 10; i++)
{
dict.Add("var" + i.ToString(), 20);
}
Some examples of usage:
dict["var1"] // 20
dict["var2"] // 20
dict.ContainsKey("var3") // true
dict.ContainsKey("var99") // false
Note: I'm concatenating the string "var" with the int from the loop just to demonstrate that you can use arbitary strings as keys to store / lookup the values. In this case it's a bit of a strange thing to do, and you'd probably be best sticking to a normal array, but my example shows how a dictionary could work with more complex keys.
If you want to bypass static type checking and you feel like creating some coding horror, you can use ExpandoObject combined with the dynamic keyword. Won't let you set variables in your scope, but will technically let you declare your own ones. Note that in my example I cast it to IDictionary<string, object> because I create its members' names at runtime from a string. What the following method does is create twenty members and assign their values from 0 to 19.
static dynamic SetVariables(IEnumerable<int> range)
{
const string variableName = "var_";
var expandoDictionary = new ExpandoObject() as IDictionary<string, object>;
foreach (var i in range)
expandoDictionary[variableName + i] = i;
return expandoDictionary;
}
You can then access the members easily this way:
var container = SetVariables(Enumerable.Range(0, 20));
var value13 = container.var_13;
Please note that I do not recommend this usage, and I'd stay away from dynamic as much as I can. However, for the sake of problem solving, this can be seen as one unsafe but partial solution.
typedef struct {
int e1;
int e2;
int e3;
int e4;
int e5;
} abc;
void Hello(abc * a, int index)
{
int * post = (&(a->e1) + index);
int i;
for(i = 0; i<5; i++)
{
*(post + i) = i;
}
}
The problem I face here is how they able to access the next element in the struct by
*(post + i)
I'm not sure how all these would be done in C# and moreover, I don't want to use unsafe pointers in C#, but something alternate to it.
Thanks!
You should replace the struct with an array of 5 elements.
If you want to, you can wrap the array in a class with five properties.
edit...
When you say 'Wrap,' it generally means to write properties in a class that set or get the value of either a single variable, an array element, or a member of another class whose instance lives inside your class (the usual usage here = 'wrap an object'). Very useful for separating concerns and joining functionality of multiple objects. Technically, all simple properties just 'wrap' their private member variables.
Sample per comment:
class test
{
int[] e = new int[5];
public void Hello(int index)
{
for (int i = 0; i <= 4; i++) {
// will always happen if index != 0
if (i + index > 4) {
MsgBox("Original code would have overwritten memory. .Net will now blow up.");
}
e[i + index] = i;
}
}
public int e1 {
get { return e[0]; }
set { e[0] = value; }
}
public int e2 {
get { return e[1]; }
set { e[1] = value; }
}
//' ETC etc etc with e3-e5 ...
}
The problem with the C code is that if index is greater than 0 it runs off the end of the abc struct, thus overwriting random memory. This is exactly why C#, a safer language, does not allow these sorts of things. The way I'd implement your code in C# would be:
struct abc
{
public int[] e;
}
void Hello(ref abc a, int index)
{
a.e = new int[5];
for (int i = 0; i < 5; ++i)
a.e[index + i] = i;
}
Note that if index > 0, you'll get an out of bounds exception instead of possibly silent memory overwriting as you would in the C snippet.
The thinking behind the C codes is an ill fit for C#. The C code is based on the assumption that the fields of the struct will be placed sequentially in memory in the order defined the fields are defined in.
The above looks like either homework or a contrived example. Without knowing the real intent it's hard to give a concrete example in C#.
other examples here suggest changing the data structure but if you can't/don't want to do that, you can use reflection combined with an array of objects of the struct type to accomplish the same result as above.
void Hello(abc currentObj){
var fields = typeof(abc).GetFields();
for(var i = 0;i<fields.Length;i++){
fields[i].SetValue(currentObj,i);
}
}