how set value in dictionary when content a dictionary and class - c#

I defined the variable below:
Dictionary<clssMenu_Item, Dictionary<clssMenu_Item, List<clssMenu_Item>>> dicMenu =
new Dictionary<clssMenu_Item, Dictionary<clssMenu_Item, List<clssMenu_Item>>>();
The type clssMenu_Item is defined as:
class clssMenu_Item
{
public string name;
public string text;
}
I have a string (I call strKey) already assigned to the text property of clssMenu_Item inside dicMenu. It's clear text is part of key. I want to search dicMenu to find value of strKey in all over of dictionary such as its sub. I don't know how can get this value?!
this method calculates the key of the dictionary:
private List<clssMenu_Item> GetFormButtons(Form form)
{
List<clssMenu_Item> ListBtn = new List<clssMenu_Item>();
foreach (Control c in GetAllControls<Button>(form))
{
int btnIndex= c.Name.IndexOf("btn");
if (btnIndex != 0) // find all of the determined buttons
{
clssMenu_Item objBtn = new clssMenu_Item();
objBtn.name = c.Name.ToString();
objBtn.text = c.Text;
ListBtn.Add(objBtn);
}
}
return ListBtn;
}
here is how I populate the key:
foreach (var k in objH.mainForm) //fill dicMenu
{
dicMenu.Add(k,null);
}
The reason that I'm using a nested dictionary is that this tree has only 3 levels. Each clssMenu_Items has a group of children like itself type. dictionary was my solution to save them.
problem:
now I wanna fill value of keys by below code:
Dictionary<clssMenu_Item, List<clssMenu_Item>> d2 = new Dictionary<clssMenu_Item, List<clssMenu_Item>>();
clssMenu_Item k = new clssMenu_Item();
k.text = strKey;
foreach(var prp in dicMenu.Keys) //we should fill all of the variables in class
{
if (prp.text == strKey)
{ k.name = prp.name; break; }
}
d2= dicMenu[k]; //assign value of key
I dont know why I have error on d2= dicMenu[k]; said k is not in DicMenu, although I debug this block. we have k in DicMenu :( I dont know what should I do?!
is there other way to create a tree?

Related

C# examining and replacing tuple values based on other tuple

I'm starting with programming and C# and I have two tuples. One tuple is representing a list of points:
static List<(string, string, string)> PR { get; set; } = new List<(string, string, string)>()
{
("P1", "0", "0"),
("P2", "P1", "P1+Height"),
("P3", "P1+Width", "P2"),
("P4", "P3", "P3+Height")
};
where Item1 in the list of tuples stands for a Point name (P1, P2, P3, P4) and Item2 and Item3 represent a parametric formula for respectively the x- and y-value of a point.
"P1" in the second item in the above list should look for the tuple starting with "P1", and then for the second item in that tuple, in this case, 0.
I have a second list of tuples that represent the parameters that I need to calculate the above point values.
static List<(string, double)> PAR { get; set; } = new List<(string, double)>()
{
("Height", 500),
("Width", 1000)
};
Say I want to calculate the value of the parametric formula "P3+Height" as follows:
P3+Height --> P2 (+Height) --> P1+Height (+Height) --> 0 (+Height (+Height) --> 0 + Height + Height;
In the end I want to replace the parameter strings with the actual values (0 + 500 + 500 -> P3+Height = 1000) but thats of later concern.
Question: I'm trying to make a function that recursively evaluates the list of tuples and keeps the parameter names, but also looks for the corresponding tuple until we reach an end or exit situation. This is where I'm at now but I have a hard time getting my thought process in actual working code:
static void Main(string[] args)
{
//inputString = "P3+Height"
string inputString = PR[3].Item3;
string[] returnedString = GetParameterString(inputString);
#region READLINE
Console.ReadLine();
#endregion
}
private static string[] GetParameterString(string inputString)
{
string[] stringToEvaluate = SplitInputString(inputString);
for (int i = 0; i < stringToEvaluate.Length; i++)
{
//--EXIT CONDITION
if (stringToEvaluate[0] == "P1")
{
stringToEvaluate[i] = "0";
}
else
{
if (i % 2 == 0)
{
//Check if parameters[i] is point string
var value = PAR.Find(p => p.Item1.Equals(stringToEvaluate[i]));
//Check if parameters[i] is double string
if (double.TryParse(stringToEvaluate[i], out double result))
{
stringToEvaluate[i] = result.ToString();
}
else if (value == default)
{
//We have a point identifier
var relatingPR = PR.Find(val => val.Item1.Equals(stringToEvaluate[i])).Item2;
//stringToEvaluate[i] = PR.Find(val => val.Item1.Equals(pointId)).Item2;
stringToEvaluate = SearchParameterString(relatingPR);
}
else
{
//We have a parameter identifier
stringToEvaluate[i] = value.Item2.ToString();
}
}
}
}
return stringToEvaluate;
}
private static string[] SplitInputString(string inputString)
{
string[] splittedString;
splittedString = Regex.Split(inputString, Delimiters);
return splittedString;
}
Can anyone point me in the right direction of how this could be done with either recursion or some other, better, easier way?
In the end, I need to get a list of tuples like this:
("P1", "0", "0"),
("P2", "0", "500"),
("P3", "1000", "500"),
("P4", "1000", "1000")
Thanks in advance!
I wrote something that does this - I changed a bit of the structure to simplify the code and runtime, but it still returns the tuple you expect:
// first I used dictionaries so we can search for the corresponding value efftiantly:
static Dictionary<string, (string width, string height)> PR { get; set; } =
new Dictionary<string, (string width, string height)>()
{
{ "P1", ("0", "0") },
{ "P2", ("P1", "P1+Height")},
{ "P3", ("P1+Width", "P2") },
{ "P4", ("P3", "P3+Height") }
};
static Dictionary<string, double> PAR { get; set; } = new Dictionary<string, double>()
{
{ "Height", 500 },
{ "Width", 1000 }
};
static void Main(string[] args)
{
// we want to "translate" each of the values height and width values
List<(string, string, string)> res = new List<(string, string, string)>();
foreach (var curr in PR)
{
// To keep the code generic we want the same code to run for height and width-
// but for functionality reasons we need to know which it is - so sent it as a parameter.
res.Add((curr.Key,
GetParameterVal(curr.Value.width, false).ToString(),
GetParameterVal(curr.Value.height, true).ToString()));
}
#region READLINE
Console.ReadLine();
#endregion
}
private static double GetParameterVal(string inputString, bool isHeight)
{
// for now the only delimiter is + - adapt this and the code when \ as needed
// this will split string with the delimiter ("+height", "-500", etc..)
string[] delimiters = new string[] { "\\+", "\\-" };
string[] stringToEvaluate =
Regex.Split(inputString, string.Format("(?=[{0}])", string.Join("", delimiters)));
// now we want to sum up each "part" of the string
var sum = stringToEvaluate.Select(x =>
{
double result;
int factor = 1;
// this will split from the delimiter, we will use it as a factor,
// ["+", "height"], ["-", "500"] etc..
string[] splitFromDelimiter=
Regex.Split(x, string.Format("(?<=[{0}])", string.Join("|", delimiters)));
if (splitFromDelimiter.Length > 1) {
factor = int.Parse(string.Format($"{splitFromDelimiter[0]}1"));
x = splitFromDelimiter[1];
}
if (PR.ContainsKey(x))
{
// if we need to continue recursively translate
result = GetParameterVal(isHeight ? PR[x].height : PR[x].width, isHeight);
}
else if (PAR.ContainsKey(x))
{
// exit condition
result = PAR[x];
}
else
{
// just in case we didnt find something - we should get here
result = 0;
}
return factor * result;
}).Sum();
return sum;
}
}
}
I didnt add any validity checks, and if a value wasn't found it recieves a val of 0, but go ahead and adapt it to your needs..
Here a a working example for your question... It took me a lot of time so I hope you appreciate it: The whole code is comented line by line. If you have any question do not hesitate to ask me !
First of all we create a class named myEntry that will represent an entry. The name has to be unique e.g P1, P2, P3
public class myEntry
{
public string Name { get; private set; } //this field should be unique
public object Height { get; set; } //Can contain a reference to another entry or a value also as many combinations of those as you want.
// They have to be separated with a +
public object Width { get; set; } //same as for height here
public myEntry(string name, object height, object width)
{
//Set values
this.Name = name;
this.Height = height;
this.Width = width;
}
}
Now I create a dummy Exception class for an exception in a further class (you will see the use of this further on. Just ignore it for now)
public class UnknownEntry : Exception
{
//Create a new Class that represents an exception
}
Now we create the important class that will handle the entries and do all the work for us. This might look complicated but if you don't want to spend time understanding it you can just copy paste it, its a working solution!
public class EntryHolder
{
private Dictionary<string, double> _par = new Dictionary<string, double>(); //Dictionary holding our known variables
private List<myEntry> _entries; //List holding our entries
public EntryHolder()
{
_entries = new List<myEntry>(); //Create list
//Populate dictionary
_par.Add("Height", 500);
_par.Add("Width", 1000);
}
public bool Add(myEntry entry)
{
var otherEntry = _entries.FirstOrDefault(x => x.Name.Equals(entry.Name)); //Get entry with same name
if(otherEntry != null)
{
//Entry with the same name as another entry
//throw new DuplicateNameException(); //Throw an exception if you want
return false; //or just return false
}
//Entry to add is valid
_entries.Add(entry); //Add entry
return true; //return success
}
public void Add(List<myEntry> entries)
{
foreach (var entry in entries) //Loop through entries
{
Add(entry);
}
}
public myEntry GetEntry(string uniqueName)
{
var entry = GetRawEntry(uniqueName); //Get raw entry
var heightToCalculate = entry.Height.ToString(); //Height to calculate to string
var widthToCalculate = entry.Width.ToString(); //Width to calculate to string
entry.Height = Calculate(heightToCalculate, true); //Calculate height
entry.Width = Calculate(widthToCalculate, false); //Calculate width
return entry; //return entry
}
public List<myEntry> CalculateAllEntries()
{
List<myEntry> toReturn = new List<myEntry>(); //Create list that we will return after the calculation finished
foreach (var entryToCalculate in _entries) //Loop through all entries
{
toReturn.Add(GetEntry(entryToCalculate.Name)); //calculate entry values and add them to the list we will return after
}
return toReturn; //return list after the whole calculation finished
}
private double Calculate(string toCalculate, bool isHeight)
{
if (!toCalculate.Contains("+"))
{
//String doesn't contain a + that means it has to be a number or a key in our dictionary
object toConvert = toCalculate; //Set the object we want to convert to double
var entryCorrespondingToThisValue = _entries.FirstOrDefault(x => x.Name.Equals(toCalculate)); //Check if the string is a reference to another entry
if (entryCorrespondingToThisValue != null)
{
//It is the name of another object
toConvert = isHeight ? entryCorrespondingToThisValue.Height : entryCorrespondingToThisValue.Width; //Set object to convert to the height or width of the object in entries
}
try
{
return Convert.ToDouble(toConvert); //try to convert and return if success
}
catch (Exception e)
{
//the given height object has the wrong format
//Format: (x + Y + z ...)
throw new FormatException();
}
}
//Contains some +
var spitedString = toCalculate.Split(new char[] {'+'}); //Split
double sum = 0d; //Whole sum
foreach (var splited in spitedString) //Loop through all elements
{
double toAdd = 0; //To add default = 0
if (_par.ContainsKey(splited)) //Check if 'splited' is a key in the dictionary
{
//part of object is in the par dictionary so we get the value of it
toAdd = _par[splited]; //get value corresponding to key in dictionary
}
else
{
//'splited' is not a key in the dictionary
object toConvert = splited; //set object to convert
var entryCorrespondingToThisValue = _entries.FirstOrDefault(x => x.Name.Equals(splited)); //Does entries contain a reference to this value
if (entryCorrespondingToThisValue != null)
{
//It is a reference
toConvert = isHeight ? entryCorrespondingToThisValue.Height : entryCorrespondingToThisValue.Width; //Set to convert to references height or width
}
try
{
toAdd = Convert.ToDouble(toConvert); //Try to convert object
}
catch (Exception e)
{
//A part of the given height is not a number or is known in the par dictionary
throw new FormatException();
}
}
sum += toAdd; //Add after one iteration
}
return sum; //return whole sum
}
public myEntry GetRawEntry(string uniqueName)
{
var rawEntry = _entries.FirstOrDefault(x => x.Name.Equals(uniqueName)); //Check for entry in entries by name (unique)
if (rawEntry == null)
{
//Entry is not in the list holding all entries
throw new UnknownEntry(); //throw an exception
return null; //Or just return null
}
return rawEntry; //return entry
}
}
And here the end, the test and prove that it works:
public void TestIt()
{
List<myEntry> entries = new List<myEntry>()
{
new myEntry("P1", 0, 0),
new myEntry("P2", "P1", "P1+Height"),
new myEntry("P3", "P1+Height", "P2"),
new myEntry("P4", "P3", "P3+Height"),
};
EntryHolder myEntryHolder = new EntryHolder();
myEntryHolder.Add(entries);
var calculatedEntries = myEntryHolder.CalculateAllEntries();
}
Here an image of how it looks like:

Dynamic Class identifier based on variable

I have the following function below that I'm trying to make and fill a class called User.
I want the Class Identifier to be dynamically named for each user there is.
The datatable that is being passed in contains informations like below.
USER | CONTROLNUMBER
"jsmith" | "789842"
I want to make a class named "JSmith" and fill the properties in that class accordingly.
I am extremely new to using classes in useful way, so be gentle.
public static void FillUserListClass(DataTable dt, string _userName)
{
User _userName = new User();
_userName.ControlNumber = "789842";
_userName.UserName = "jsmith";
}
Would something like this be right for the dictionary of list idea?
static Dictionary<string, List<int>> UserList = new Dictionary<string, List<int>>();
public static void FillUserListClass(DataTable dt)
{
for (int ctr = 0; ctr < dt.Rows.Count; ctr++)
{
var row = dt.Rows[ctr];
var userName = row["User"].ToString();
if (UserList.ContainsKey(userName))
{
UserList[userName].Add(Convert.ToInt32(row["ControlNumber"]));
}
else
{
UserList.Add(row["User"].ToString(), new List<int>());
UserList[userName].Add(Convert.ToInt32(row["ControlNumber"]));
}
}
And if so, how would i print out the dictionary so you would see something similar to
'jsmith' has 4 control numbers.
"234950"
"494602"
"494200"
"585890"

Sending a list of doubles as strings to the database

Just quite confused with the piece of code below.
I have class like below
public class Counter
{
public Double NormalCounter { get; set; }
public Double SATCounter { get; set; }
public Double SUNCounter { get; set; }
}
in my main class i have method to do some calculation to fill the counter
Counter CountHrs = GetBookedHours(resourceBkg, PrevEvent);
var lstExpResult = new List<string> {CountHrs.NormalCounter.ToString(),
CountHrs.SATCounter.ToString(),
CountHrs.SUNCounter.ToString()};
UpdateBooking(bookingSesid, lstExpResult);
Just assume i have the value like below in the counter
NormalCounter =4
SATCounter=10
SUNCounter=6
am trying to add in to string list and update the database.is that the right way to do ? or any other options i have please.
my update booking method is below to give clear idea.
public static bool UpdateBooking(string BookingSesid,List<string>HoursByRate)
{
SchedwinEntities db = new SchedwinEntities();
string value = string.Empty;
for (int i = 0; i < 5; i++)
{
string str = " ";
if (i < HoursByRate.Count())
{
str = HoursByRate[i];
value += str + ((char)13).ToString() + ((char)10).ToString();
}
}
var query =
from SEVTs in db.SEVTs
where
SEVTs.SESID.Trim() == BookingSesid//SESID
select SEVTs;
foreach (var SEVTs in query)
{
SEVTs.USER3 = value;//value
}
try
{
db.SaveChanges();
return true;
}
catch (UpdateException ex)
{
return false;
}
}
Rather than passing a list of strings that represent doubles, you should pass a list of key-value pairs, construct a parametersized statement from them, and use the list of key-value-pairs to bind parameter values, like this:
class SqlParamBinding {
string Name {get;set;}
object Value {get;set;}
}
var lstExpResult = new List<SqlParamBinding> {
new SqlParamBinding { Name = "NormalCounter", Value = CountHrs.NormalCounter}
, new SqlParamBinding { Name = "SATCounter", Value = CountHrs.SATCounter}
, new SqlParamBinding { Name = "SUNCounter", Value = CountHrs.SUNCounter}
};
UpdateBooking(bookingSesid, lstExpResult);
Now that lstExpResult separates names from values, your UpdateBooking code could format the SQL expression as
WHERE NormalCounter=#NormalCounter AND SATCounter=#SATCounter AND ...
and then bind #NormalCounter, #SATCounter, and #SUNCounter to the values passed in the lstExpResult list.
If it is going to list of Counter classes then have List instead of List. Looks like you might be having bunch of Counter objects that might be getting updated or sent to the database.
Counter c = new Counter();
c. NormalCounter = 4
c.SATCounter = 10
c.SunCounter = 10
List<Counter> listCounter = new List<Counter>
listCounter.Add(c);
Code is more maintainable and readable.
If you are sending one object at a time, then no need of list at all. You can pass in the counter object to your UpdateMethod and parse it while updating the database.

increasing names in C# with integers

I need to get an object and check if it already exists.
In case it does, I want to add a number, or increase the number in its name.
For example if I have the object "a" and it exists, I need to add a 1 so it's called a1.
In case a1 exists, a2, etc.
How could I perform this?
My code:
if (e.TreeNode.Tag is Variant)
{
if (variantExists(e.TreeNode.Text))
{
Random r = new Random();
int randomNumber = r.Next(0, 99);
e.TreeNode.Text = e.TreeNode.Text + randomNumber;
//e.TreeNode.Remove();
return;
}
}
Can you change the TreeNode class? I would add properties for Label (Name without Index) and Index and make the Name property read only, i.e
class TreeNode
{
public int Index {get;set;}
public string Label {get;set;}
public string Name
{
get { return Index == 0 ? Label : Label + Index; }
}
}
In your code you just need to set the Index property to the value you need and dont worry about the whole string parsing stuff
string name = "SomeName";
string tempName = name;
int n = 0;
while (DoesNameExist(tempName))
{
n++;
tempName = name + n;
}
name = tempName;
This gets ineffecient for large numbers of the same object, but that shouldn't happen right?
The problem with doing it the other way around, and stripping off trailing numbers to find the "original" name is that the original name may genuinely have numbers on it.
Eg. You say you add:
SomeName
SomeName99
SomeName
SomeName99
The above code will give you
SomeName
SomeName1
SomeName99
SomeName991
Something along the lines of this could work:
var existingItems = new HashSet<string>();
var items = new List<string>{"a", "b", "a"};
foreach (var item in items)
{
var tempItem = item;
var i = 1;
while (!existingItems.Add(tempItem))
tempItem = tempItem + i++;
}

Get value from dictionary key while for each and its element is string

how can I get value from key while the element in for each is just a string?
Here is my code:
public List<int[]> FindAllLetters(List<string> lettersOnBoard, Dictionary<string, int> frequency)
{
List<int[]> lettersExistLeft = new List<int[]>();
foreach (string letter in frequency.Keys)
{
int exist = 0;
int dictionaryFrquencyLetter = 0;
exist = lettersOnBoard.Count(n => n == letter);
dictionaryFrquencyLetter = letter.GiveValueOfKey() //< how get value of key(letter) ?
}
throw new NotImplementedException();
}
Is it somehow possible?
Have you tried this?
dictionaryFrquencyLetter = frequency[letter];
The same way you get any value from a dictionary with a given key:
dictionaryFrquencyLetter = frequency[letter];
However (assuming that the rather pointless code you have posted will be extended at some point to do something useful) if you are iterating through the dictionary keys collection why not just iterate through the items e.g.
foreach (var item in frequency)
{
var key = item.Key
var value = item.Value
}
It sounds like you are looking for this:
dictionaryFrquencyLetter = frequency[letter];

Categories

Resources