0

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.

Jack Clarke
  • 55
  • 1
  • 9
  • First thing I would do, is check if the dictionary already contains the key you are trying to add, as if it does, your current code will throw an exception, I will add my own sample below to try and prevent exceptions. – Ryan Wilson Mar 12 '18 at 14:57
  • Hi Ryan, I have already done that, I will add the code to the main body, thank you. – Jack Clarke Mar 12 '18 at 14:58
  • If I had to contribute to a project with such a datastructure, I'd ask if this is really necessary. Seems overly complicated. – Fildor Mar 12 '18 at 14:59
  • 4
    I'm not 100% sure what you are trying to accomplish, however I've tried using dictionaries of tuples before and always kicked myself for not using a Class instead. – Matt Mar 12 '18 at 14:59
  • 2
    You should also think into replacing the `Tuple` with an actual class. Right now you are creating a `Tuple` and modifying values inside but `Tuple` is immutable so since the items are `List` it works but if you change something it will stop working it is quite confusing. – Franck Mar 12 '18 at 14:59
  • For readability, consider using C#7.0 syntax for declaring (named) Tuples `var dict = new Dictionary name1, List name2)> `. Instead of constantly needing to reference `Item1` or `Item2` – ethane Mar 12 '18 at 14:59
  • @ethane Thanks for the tip, I will start using this. – Jack Clarke Mar 12 '18 at 15:05
  • @Franck I will start looking into this as well, thank you for the suggestion. It doesn't answer my main question about dynamically naming dictionary Keys though, is my current method the most reliable way of doing this? – Jack Clarke Mar 12 '18 at 15:07
  • This code could benefit a lot from local variables. No need to lookup which column has ID `"CSN"` 6 times and perform conversion to string 6 times in each loop iteration. Plus the result will be much more readable. – Ben Voigt Mar 12 '18 at 15:21
  • @BenVoigt Thanks for the feedback, you are completely correct. Amended code in body. – Jack Clarke Mar 12 '18 at 17:23

1 Answers1

0

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());
            }
        }
    }
Ryan Wilson
  • 10,223
  • 2
  • 21
  • 40
  • @JackClarke As far as I can see, checking if the key exists and then adding it with new initialized lists is as reliable as it's going to get, but I did offer a condensed version of your current code. – Ryan Wilson Mar 12 '18 at 15:16
  • Thank you very much, that's great. I really appreciate your help. New to C# so seeing your much more efficiently typed code really helps! – Jack Clarke Mar 12 '18 at 15:47
  • @JackClarke Glad I could help. – Ryan Wilson Mar 12 '18 at 15:50