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.
Related
Reviewing one opensource project, I've come across one interesting Data structure:
// Represents a layer of "something" that covers the map
public class CellLayer<T> : IEnumerable<T>
{
public readonly Size Size;
public readonly TileShape Shape;
public event Action<CPos> CellEntryChanged = null;
readonly T[] entries;
public CellLayer(Map map)
: this(map.TileShape, new Size(map.MapSize.X, map.MapSize.Y)) { }
public CellLayer(TileShape shape, Size size)
{
Size = size;
Shape = shape;
entries = new T[size.Width * size.Height];
}
public void CopyValuesFrom(CellLayer<T> anotherLayer)
{
if (Size != anotherLayer.Size || Shape != anotherLayer.Shape)
throw new ArgumentException(
"layers must have a matching size and shape.", "anotherLayer");
if (CellEntryChanged != null)
throw new InvalidOperationException(
"Cannot copy values when there are listeners attached to the CellEntryChanged event.");
Array.Copy(anotherLayer.entries, entries, entries.Length);
}
// Resolve an array index from cell coordinates
int Index(CPos cell)
{
return Index(cell.ToMPos(Shape));
}
// Resolve an array index from map coordinates
int Index(MPos uv)
{
return uv.V * Size.Width + uv.U;
}
/// <summary>Gets or sets the <see cref="OpenRA.CellLayer"/> using cell coordinates</summary>
public T this[CPos cell]
{
get
{
return entries[Index(cell)];
}
set
{
entries[Index(cell)] = value;
if (CellEntryChanged != null)
CellEntryChanged(cell);
}
}
/// <summary>Gets or sets the layer contents using raw map coordinates (not CPos!)</summary>
public T this[MPos uv]
{
get
{
return entries[Index(uv)];
}
set
{
entries[Index(uv)] = value;
if (CellEntryChanged != null)
CellEntryChanged(uv.ToCPos(Shape));
}
}
/// <summary>Clears the layer contents with a known value</summary>
public void Clear(T clearValue)
{
for (var i = 0; i < entries.Length; i++)
entries[i] = clearValue;
}
public IEnumerator<T> GetEnumerator()
{
return (IEnumerator<T>)entries.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
This structure represents a matrix of type T in that, given a CPos (an X,Y) structure, it returns the T element at that position. Here's one sample usage:
var dic = new CellLayer<CellInfo>(TileShape.Rectangle, new Size(1280,1280));
cellLayer[new CPos(0, 1)] = new CellInfo(0, new CPos(0, 1), false);
Internally, the CellLayer class transforms the given CPos into a int which operates as the index for the internal array.
By the looks of how the class operates from a client-side perspective, it felt to me like a Dictionary, so I replaced the implementation. After several runtimes tests and microbenchmarking, it turned out that using the dictionary was dozens of times slower than using the handmade CellLayer class. That surprised me. Here are the tests I did:
[Test]
public void DictionaryTest()
{
var dic = new Dictionary<CPos, CellInfo>(1280 * 1280);
var watch = Stopwatch.StartNew();
for (int i = 0; i < 1280; i++)
for (int u = 0; u < 1280; u++)
dic[new CPos(i, u)] = new CellInfo(0, new CPos(i, u), false);
Console.WriteLine(watch.ElapsedTicks);
}
[Test]
public void CellLayerTest()
{
var dic = new CellLayer<CellInfo>(TileShape.Rectangle, new Size(1280,1280));
var watch = Stopwatch.StartNew();
for (int i = 0; i < 1280; i++)
for (int u = 0; u < 1280; u++)
dic[new CPos(i, u)] = new CellInfo(0, new CPos(i, u), false);
Console.WriteLine(watch.ElapsedTicks);
}
I thought that .NET Collections were as optimized as possible. Can anyone explain to me how is it that using Dictionary is slower that using a "custom Dictionary"?
Thanks
For the original version, you find the location of an entry by using this formula
uv.V * Size.Width + uv.U
To find the location in a dictionary
Calculate the hash code for CPos.
Find the bucket in the dictionary using a modulus operation hashcode % dictionarySize
If the bucket isn't empty, compare the CPos you have with the CPos in that bucket. If they don't match you have a secondary hash code collision. Move to the next bucket and retry step 3.
If you have a primary has code collision, which is to say lots of different CPos values have the same hash code, your dictionary is going to be ridiculously slow.
If you have unique hash codes, then it is probably the modulus operation that is killing performance. But you would need to attach a profiler (e.g. Redgate ANTS) to find out for sure.
A dictionary maintains an search/retrievable set of itmes (either through a hash-table, a binary tree or something similar). So each Add() and each [key] implies some search (which tends to be relatively "slow").
In your case, if there is a simple mapping from a CPos to an integer (aka array index) there is no search but a direct (and fast) access to a cell of an array.
Or, to put it simpler: Essentially you compare a hash table/binary tree against a flat array.
Edit
Of course both collections are rather fast and show O(1) compexity. A lookup in a hash table is more complex than an array index operation however.
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]);
}
I've been trying to write a program which can scan a raw data file and normalize it for data mining processes, I've trying to read the data from the file and store it in a list this way:
public static List<Normalize> NF()
{
//Regex r = new Regex(#"^\d+$");
List<Normalize> N = new List<Normalize>();
StreamReader ss = new StreamReader(#"C:\Users\User\Desktop\NN.txt");
String Line = null;
while (!ss.EndOfStream) {
Line = ss.ReadLine();
var L = Line.Split(',').ToList();
N.Add(new Normalize { age = Convert.ToInt16(L[0]),
Sex = L[1],
T3 = Convert.ToDouble(L[2]),
TT4 = Convert.ToDouble(L[3]),
TFU = Convert.ToDouble(L[4]),
FTI = Convert.ToDouble(L[5]),
RC = L[6],
R = L[7]
});
}
return N;
}
}
struct Normalize {
public int age;
public String Sex;
public double T3;
public double TT4;
public double TFU;
public double FTI;
public String RC;
public String R;
}
At this moment I want to go through the list that I've made and categorize the data , similar to this :
var X= NF();
for (int i = 0; i < X.Count; i++) {
if (X[i].age > 0 && X[i].age <= 5) { // Change the X[i].age value to 1 }
else if (X[i].age > 5 && X[i].age <= 10) { // Change the X[i].age value to 2 }
...
}
But the compiler says X[i].[variable name] is not a variable and cannot be modified in this way. My question is, what would be an efficient way to perform this operation.
struct Normalize is a value type, not a reference type, therefore you cannot change its fields like that. Change it to class Normalize
Change struct Normalize to class Normalize and iterate with foreach loop. It's way cleaner.
You could also set variables to private and use getters/setters to check/set variable.
foreach (Normalize x in X)
{
if (x.getAge() > 0 && x.getAge() <= 5)
x.setAge(1)
...
}
Edit:
just saw you already got your answer
Modifying struct field is fine as long as it's a single entity (Given its a mutable struct). This is possible -
var obj = new Normalize();
obh.Age = 10;
But in your case you are accessing the struct using indexer from the list.
Indexer will return copy of your struct and modifying the value won't reflect it back to the list which ain't you want.
Hence compiler is throwing error to stop you from writing this out.
As Alex mentioned, you should go for creating class instead of struct if you want to modify it.
On a side note, its always advisable to have immutable structs instead of mutable structs.
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);
}
}