I have the code below which is intended to build a dictionary object with the following construction Dictionary<string<Dictionary<string, string>. For some reason each time I add an item to it the key text is correct but the value (dictionary) overwrites the previous one. This is probably better explained like this:
Iteration 1
key1, dictionary1
Iteration 2
key1, dictionary2
key2, dictionary2
Iteration 3
key1, dictionary3
key2, dictionary3
key3, dictionary3
What is causing this and how can I fix this code to stop it overwriting the dictionary in each entry?
QueryNameUserQueryString = new Dictionary<string, string>();
DialectDictionary = new Dictionary<string, Dictionary<string, string>>();
while (dataBaseConnection.NextRecord())
{
if (QueryNameUserQueryString != null)
{
QueryNameUserQueryString.Clear();
}
string dialect = dataBaseConnection.GetFieldById (0);
//If no dialect then carry out next iteration
if (String.IsNullOrEmpty (dialect))
{
continue;
}
try
{
dataBaseConnection2.ExecutePureSqlQuery ("SELECT * FROM " + sqlFactoryTable + " WHERE SQL_FACTORY_DIALECT = '" + dialect + "'");
}
catch
{
dataBaseConnection.Close();
dataBaseConnection2.Close();
throw;
}
//Do we have query strings for this dialect?
if (!dataBaseConnection2.HasRows())
{
continue;
}
//loop through query strings
while (dataBaseConnection2.NextRecord())
{
string queryName = dataBaseConnection2.GetFieldById (2);
string queryString = dataBaseConnection2.GetFieldById (3);
string user = dataBaseConnection2.GetFieldById (4);
//create composite key for dictionary
string compositeKey = dialect + "," + queryName + "," + user;
if (QueryNameUserQueryString != null)
{
//Construct our query string dictionary
QueryNameUserQueryString.Add (compositeKey, queryString);
}
}
//If we have a query string dictionary
if (QueryNameUserQueryString != null)
{
//Ensure m_dialect dictionary is not null
if (DialectDictionary != null)
{
//Construct our dictionary entry for this dialect
DialectDictionary.Add (dialect, QueryNameUserQueryString);
}
}
}
}
You seem to be using the same instance of QueryNameUserQueryString on every iteration. When it's added to the DialectDictionary, it's added as a reference - not a copy of the original.
To "properly" solve the issue, I would move the declaration of your QueryNameUserQueryString variable inside the while-scope. That way you would make sure that it can only exist in the scope of a single iteration, not across several. When it's added to the DialectDictionary, the reference lives on in that dictionary and you're safe to leave the scope.
You are using same instance of QueryNameUserQueryString everytime. Replace
QueryNameUserQueryString.Clear();
with
QueryNameUserQueryString = new Dictionary<string, string>();
Related
I have created a Dictionary called 'sGC' that has a string key and a value of a Tuple containing 2 lists of strings.
Dictionary<string, Tuple<List<string>, List<string>>> sGC = new Dictionary<string, Tuple<List<string>, List<string>>>();
I want to add new keys to this dictionary that are concatenated strings from a DataTable DataRow (DR). If a certain criteria is met then a string from the DR goes in either Item1 or Item2 of the Tuple.
This code is being executed in a foreach loop iterating through the DataTable, stopping on certain rows if the row meets an if statement criteria.
var dicTup = new Tuple<List<string>,List<string>>(new List<string>(), new List<string>());
dicTup.Item2.Add(DR["PupilID"].ToString());
sGC.Add(DR["CSN"].ToString() + DR["AW2"].ToString(), dicTup);
Is this the best way to add new dynamically named keys to the dictionary?
I believe the top answer from this JavaScript thread is an answer that I am looking for in C#: How to create dictionary and add key–value pairs dynamically?
Full code below.
foreach (DataRow DR in MainData.DataTable.Rows)
{
//Rows containing a symbol mark score
if ((DR["CN"].ToString() == "LC") && (DR["AW2"].ToString() != ""))
{
//Store male results
//If the Subject Name + Level Code is already a key in the dictionary, append to Tuple List 1
//If key does not exist in Dictionary, create new DictKey and value
if (DR["PG"].ToString() == "Male")
{
if (sGC.ContainsKey(DR["CSN"].ToString() + DR["AW2"].ToString()))
{
sGC[DR["CSN"].ToString() + DR["AW2"].ToString()].Item1.Add(DR["PID"].ToString());
}
else
{
var dicTup = new Tuple<List<string>,List<string>>(new List<string>(), new List<string>());
dicTup.Item1.Add(DR["PID"].ToString());
sGC.Add(DR["CSN"].ToString() + DR["AW2"].ToString(), dicTup);
}
}
//Store female results
//If the Subject Name + Level Code is already a key in the dictionary, append to Tuple List 2
//If key does not exist in Dictionary, create new DictKey and value
if (DR["PG"].ToString() == "Female")
{
if (sGC.ContainsKey(DR["CSN"].ToString() + DR["AW2"].ToString()))
{
sGC[DR["CSN"].ToString() + DR["AW2"].ToString()].Item2.Add(DR["PID"].ToString());
}
else
{
var dicTup = new Tuple<List<string>,List<string>>(new List<string>(), new List<string>());
dicTup.Item2.Add(DR["PupilID"].ToString());
sGC.Add(DR["CSN"].ToString() + DR["AW2"].ToString(), dicTup);
}
}
}
Newly edited and formatted code:
private void storeMarkSheetData()
{
if (MainData.DataTable != null)
{
if(subjectGradeCounts.Count == 0)
{
foreach (DataRow DR in MainData.DataTable.Rows)
{
string cN = DR["ColumnName"].ToString();
string aW2 = DR["AssessmentAwarded2"].ToString();
string cSN = DR["ClassSubjectName"].ToString();
string pID = DR["PupilID"].ToString();
string pG = DR["PupilGender"].ToString();
//Rows containing a symbol mark score
if ((cN == "Level Code") && (aW2 != ""))
{
//Check to see if the dictionary contains the key, adds it if not
if(!subjectGradeCounts.ContainsKey(cSN + aW2))
{
subjectGradeCounts.Add(cSN+aW2, new
Tuple<List<string>, List<string>>(new List<string>(), new
List<string>()));
}
//Now that the key exists, if it didn't previously
//If male add to list 1, else list 2 (for female)
if(pG == "Male")
{
subjectGradeCounts[cSN + aW2].Item1.Add(pID);
}
else
{
subjectGradeCounts[cSN + aW2].Item2.Add(pID);
}
}
}
}
}
}
Thank you all.
Here I simplified what you have to just check if the key exists, if not it adds it with new initialized lists, then does one if else for if male add to list 1 else (female) add to list 2, from the code you posted this is what I came up with
foreach (DataRow DR in MainData.DataTable.Rows)
{
//Rows containing a symbol mark score
if ((DR["CN"].ToString() == "LC") && (DR["AW2"].ToString() != ""))
{
//Check to see if your dictionary contains the key, if not, add it
if(!sGC.ContainsKey(DR["CSN"].ToString() + DR["AW2"].ToString()))
{
sGC.Add(DR["CSN"].ToString() + DR["AW2"].ToString(), new
Tuple<List<string>,List<string>>(new List<string>(), new
List<string>()));
}
//Now that the key exists, if it didn't previously
//If male add to list 1, else list 2 (for female)
if(DR["PG"].ToString() == "Male")
{
sGC[DR["CSN"].ToString() + DR["AW2"].ToString()].Item1.Add(DR["PupilID"].ToString());
}
else
{
sGC[DR["CSN"].ToString() + DR["AW2"].ToString()].Item2.Add(DR["PupilID"].ToString());
}
}
}
I have a dictionary like below where i store list of file names with key generated as Csv1,Csv2 based on number of files.
I have a string array like below :
string[] files = { "SampleCSVFile_5300kb1.csv,SampleCSVFile_5300kb2.csv", "SampleCSVFile_5300kb3.csv"};
int counter=1;
var dictionary = new Dictionary<string, string>();
foreach (var file in files)
{
dictionary.Add("CSV" + counter, file);
counter++;
}
foreach (var file in files)
{
string myValue;
if (dictionary.TryGetValue(file, out myValue)) // getting null in out value
}
When i try to search for SampleCSVFile_5300kb1.csv i am getting null in my myValue variable.
Screenshot:
Update:i realize that i was adding wrong key so changed it like below but still unable to find CSV1 in case of SampleCSVFile_5300kb1.csv:
foreach (var file in files)
{
dictionary.Add(file,"CSV" + counter);
counter++;
}
Based on the comment you said in Amir Popoviches answer. I think you should alter your dictionary construction.
So you will create a mapping from each of the .csv file(s) to the "CSV1" etc string.
var files = new[] { "SampleCSVFile_5300kb1.csv,SampleCSVFile_5300kb2.csv", "SampleCSVFile_5300kb3.csv" };
var counter = 1;
var dictionary = new Dictionary<string, string>();
foreach (var file in files)
{
if (string.IsNullOrWhiteSpace(file))
{
continue;
}
foreach (var item in file.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
{
dictionary.Add(item, "CSV" + counter);
}
counter++;
}
And as you said in comments you want to find what "CSVX" file is for each of the files you have so we simulate you trying to find a match for these files. Notice that this array has all separate file names, in the upper array we had values comma separated so we group them together.
var files2 = new[] { "SampleCSVFile_5300kb1.csv", "SampleCSVFile_5300kb2.csv", "SampleCSVFile_5300kb3.csv" };
foreach (var file in files2)
{
string csvValue;
if (dictionary.TryGetValue(file, out csvValue))
{
Console.WriteLine("{0} -> {1}", file, csvValue);
}
}
This should output you
SampleCSVFile_5300kb1.csv -> CSV1
SampleCSVFile_5300kb2.csv -> CSV1
SampleCSVFile_5300kb3.csv -> CSV2
First argument in TryGetValue is key. So you should pass there "CSV" + counter to make it works.
https://msdn.microsoft.com/pl-pl/library/bb347013(v=vs.110).aspx
You are adding items to the dictionary with the following keys:
"CSV" + counter -> CSV1, CSV2...
And you are trying to find different values (e.g. "SampleCSVFile_5300kb1.csv,SampleCSVFile_5300kb2.csv") here:
foreach (var file in files)
{
string myValue;
if (dictionary.TryGetValue(file, out myValue)) // getting null in out value
}
Try below updated code:
string[] files = { "SampleCSVFile_5300kb1.csv,SampleCSVFile_5300kb2.csv", "SampleCSVFile_5300kb3.csv" };
int counter = 1;
var dictionary = new Dictionary<string, string>();
foreach (var file in files)
{
dictionary.Add("CSV" + counter, file);
counter++;
}
counter = 1;
foreach (var file in files)
{
string myValue;
//You need to pass key name here but you are passing value of it
//Need to update here
string keyName = "CSV" + counter;
if (dictionary.TryGetValue(keyName, out myValue)) ; // getting null in out value
counter++;
}
Iterate the dictionary an find your desired value using split by comma. you will get "SampleCSVFile_5300kb1.csv" and "SampleCSVFile_5300kb2.csv" into the fileName array for the same myvalKey
foreach (KeyValuePair<string, string> entry in dictionary)
{
string myvalKey = entry.Key;
string myval = entry.Value;
if (myval.Contains(',')) {
string[] fileNames = myval.Split(',');
}
}
From what I understand you seem to be looking for a way to match only part of a key. And while I suggest using the answers of Janne Matikainen and just add the parts of your key separately with the same value, regardless I will give you a way to match on a partial key using a bit of Linq.
string resultValue = null;
string resultKey = dictionary.Keys.FirstOrDefault(k => k.Contains(file));
if(resultKey != null)
resultValue = dictionary[resultKey];
this does assume only the first match is wanted, if you want all matching keys replace FirstOrDefault with Where.
Beware that while this code is easy it is not suitable for when performance is critical as you iterate over the keys basically using the dictionary as a
List<Tuple<string,string>>
i hope you can give me a hint for my problem i have with my code.
I have a DataGridView which got its Data from an Excelfile.
Now to get structure in it, i want to make groups (keyword in dsdslls) and add valueNames (value of dsdslls and keyword in dslls) to that groups and add that content (value of dslls) to valueNames as KeyValuePair.
My Problem is not to add all that stuff, but to get it back.
here is the code (add stuff):
internal Dictionary<String, Dictionary<String, LinkedList<String>>> BuildList(DataGridView dgv)
{
//create the main Dictionary
Dictionary<String, Dictionary<String, LinkedList<String>>> dsdslls = new Dictionary<String, Dictionary<String, LinkedList<String>>>();
String groupName = "Project data", value = "", valueName = "", text = "";
//run through the whole list
for (int i = 0; i < dgv.RowCount - 1; i++)
{
//create new Dictionary for the Content
Dictionary<String, LinkedList<String>> dslls = new Dictionary<String, LinkedList<String>>();
//check if the String at i is a groupName, if so add it to groupName
if (isGroupName(dgv, i))
{
groupName = dgv.Rows[i].Cells[0].Value.ToString();
text = "Adding in group: " + groupName + " to value: ";
}
//now go forward in the list until you next Cell is empty or the list ended
do
{
//check if the String at i is a valueName, if so add it to valueName
if (isValueName(dgv, i))
{
//create the LinkedList for units and values
LinkedList<String> lls = new LinkedList<String>();
valueName = dgv.Rows[i].Cells[0].Value.ToString();
//check if group and valuename are NOT the same
if (isNotSame(valueName, groupName))
{
//now run the colums for units and values and add them to the List until you reach the end of used columns
int j = 0;
do
{
value = dgv.Rows[i].Cells[1 + j].Value.ToString();
lls.AddLast(value);
if (j == 0)
{
text += "\n" + valueName + " in (" + lls.First.Value.ToString() + "): ";
}
else
{
text += lls.Last.Value.ToString();
}
j++;
} while (j < dgv.Rows[i].Cells.Count - 1);
//add the valueName and List as new keyvaluepair to the dictionary.
dslls.Add(valueName, lls);
}
}
i++;
} while (!isStringEmpty(dgv.Rows[i].Cells[0].Value.ToString()) && i < dgv.RowCount - 1);
//show added content
MessageBox.Show(text);
//check if main dictionary contains the latest groupname, if not add the groupName and the last dictionary to the main dictionary
if (!dsdslls.ContainsKey(groupName))
{
dsdslls.Add(groupName, dslls);
}
}
MessageBox.Show("Building successfully finished.");
return dsdslls;
}
I'm not getting the right content back to the specified groupName... for example:" groupName = "Project Data" i got back the content of the group:" Electrical Network" which is the next keyword in the maindictionary
now the code to get the Data:
internal void /*Dictionary<String, LinkedList<String>>*/ GetGroupContent(Dictionary<String, Dictionary<String, LinkedList<String>>> dsdslls, String groupName)
{
//Dictionary<String, LinkedList<String>> dslls = new Dictionary<String, LinkedList<String>>();
String groupN = "", text = "";
//Check if Dictionary contains groupName
if (dsdslls.ContainsKey(groupName))
{
//run through the dictionary
foreach (var s in dsdslls)
{
//give back the keyword (just for the MessageBox)
if (s.Key == groupName)
{
groupN = s.Key;
}
else
{
//run throught the little dictionary to get the keywords from it.
foreach (var t in s.Value)
{
text += t.Key + "\n";
}
}
}
MessageBox.Show("Content of Group " + groupN + ": \n" + text);
text = "";
}
//return dslls;
}
Kind regards
Mirko
It is hard to understand what you expect from this code as the main problem is not well described.
Anyway, it seems that there might be problem in your data retrieval logic.
If you want to get data of group with matching name, then you have to move else part of your if statement. You need to do text concatenation only when group with correct name is found.
...
//give back the keyword (just for the MessageBox)
if (s.Key == groupName)
{
groupN = s.Key;
//run throught the little dictionary to get the keywords from it.
foreach (var t in s.Value)
{
text += t.Key + "\n";
}
}
...
i have a query to delete cascade, here the query
create table satuan_type
(
id int identity(1,1),
satuan_id int(200),
type_id int,
primary key(id),
foreign key(satuan_id) references satuan(id) on update cascade on delete cascade
);
the question is, how to create / add, delete and update cascade with c#?. so the query is running/crete automatically in this method
Dictionary<String, String> dic = new Dictionary<string, string>();
dic.Add("id", "INT PRIMARY KEY IDENTITY");
dic.Add("satuan_id", "INT");
dic.Add("type_id", "INT");
cDatabaseSQLServer.CreateTables("satuan_type", dic);
public int CreateTables(String tableName, Dictionary<String, String> data)
{
switch (sqlType)
{
case DATABASE_SQL_TYPE.DATABASE_SQL_TYPE_SQLITE:
return cSQLite.CreateTables(tableName, data);
case DATABASE_SQL_TYPE.DATABASE_SQL_TYPE_MSSQL:
return cSQL.CreateTables(tableName, data);
}
return 0;
}
public int CreateTables(String tableName, Dictionary<String, String> data)
{
string s = "CREATE TABLE " + tableName + " (";
bool first = true;
foreach (KeyValuePair<String, String> val in data)
{
if (first)
{
first = false;
}
else
{
s = s + ",";
}
string s1;
s1 = String.Format("{0} {1}", val.Key, val.Value);
s = s + s1;
}
s = s + ")";
return this.ExecuteNonQuery(s);
}
I think you need to add logic to your CreateTables-method. Preferably you add more parameters in which you can input any keys that you want constraints on. Cause from what I'm reading at the moment, you are not creating any constraints at all. This is possible by iterating the same logic you've already used, but for primary and foreign keys respectively - preferable with a boolean variable-flag to mark if they should be cascaded or not.
Although, I suggest you do as MSI suggested and use an ORM.
public static string filename2_1, filename2_2, filename2_3;
filename2_1="xyz.jpg";
filename2_2="abc.png";
filename2_3="qwe.jpg";
.....
...
for (int key = 1; key <= 3; key++)
{
....
foreach (var item in tabItem)
{
item.ImagePath.Value = "images1/" + ("filename2_" + key);
item.ThumbPath.Value = "thumbnails1/" + ("filename2_" + key);
}
}
As stated above I need to convert ("filename2_" + key) into actual variable. Can anyone help me regarding this
You can't have dynamic variable names.
Variable names cannot be "created".
You can use an array or a generic collection to hold the collections of data you are using.
var fileSuffixList = new List<string>{ "xyz.jpg" , "abc.png", "qwe.jpg"};
foreach(string fileSuffix in fileSuffixList)
{
....
foreach (var item in tabItem)
{
item.ImagePath.Value = "images1/" + ("filename2_" + fileSuffix);
item.ThumbPath.Value = "thumbnails1/" + ("filename2_" + fileSuffix);
}
}
As #Oded stated, you can't have dynamic variable names.
What you can do is use a Collection such as a dictionary:
Dictionary<string, int> dictionary = new Dictionary<string, string>();
dictionary.Add("filename2_" + key, "Value");
If your keys are always numeric, you can also use an array or a List. However, without more information, it's hard to tell you the best way to go about it.