简体   繁体   中英

Adding integer values from multiple lists from a Dictionary

I'm trying to work on a project in c# for my computer programming course and am stuck with part of the programming.

What I want to do is add integers stored in multiple lists together, put that into a new list, then output the average (with the lists being stored in a dictionary). For example, if I had:

List<int> list1 = new List<int>():  
List<int> list2 = new List<int>():

list1.Add(2);  
list1.Add(3);

list2.Add(1);  
list2.Add(7);

I'd want a new list that would have the sum of the int values at their specific locations, so at location 0 in the new list, the value would be 3, and at location 1 it would be 10.

Or in the same theme of my code, If Susan scored 89 on her first test and 50 on her second, and Johnny scored 100 on his first test and 89 on his second, what is the class average for test 1 and 2? (With Susan and Johnny being the keys, and each of their tests being elements in their own lists)

I don't know if it complicates things or not, but I have each list stored in a dictionary, with a string as the key (as it was easier to organize). Here's my class code:

List <int> testInfo;
Dictionary<string, List<int>> dict;
string name;
int testGrade;
int count = 0;
int count2 = 0;
int nameCount = 0;
int gradeCount = 0;

public StudentInfo() 
{

   dict = new Dictionary<string, List <int>>();
}

public void LoadGrades(string name, int testGrade) //adds the inputted values into a list
{
        this.name = name;
        this.testGrade = testGrade;
        testInfo = new List<int>();    

    if (dict.TryGetValue(name, out testInfo))
    {

        testInfo.Add(testGrade);
    }

    else
    {
        testInfo = new List<int>();  //creates a new list if a new key is entered
        testInfo.Add(testGrade);
        dict[name] = testInfo;
    }


}


public void DisplayGrades() //Displays the data entered so far
{
    Console.WriteLine("\nThis is the data you have entered so far.");
    Console.WriteLine("\n{0,-5} {1,20}", "Name", "Grade");
    Console.WriteLine("------------------------------");

    foreach (KeyValuePair<string, List<int>> pair in dict)
    {               
        foreach (int i in pair.Value)
        {
            Console.WriteLine("{0,-5} {1,20}%", pair.Key, i.ToString());
        }

    }
}

public void StuAvg() //Displays the average of each list for its specific key
{
    double average;
    Console.WriteLine("\nThese are the students averages.");

    Console.WriteLine("\n{0,-5} {1,20}", "Name", "Average");
    Console.WriteLine("------------------------------");

    foreach (KeyValuePair<string, List<int>> pair in dict)
    {
        average = Math.Round(pair.Value.Average(), 2);
        Console.WriteLine("{0,-5} {1,20}%", pair.Key, average.ToString());

    }



}

public void TestAvg() //Displays the average for each individual test
{
    List <int> testAvg = new List<int>();
    Console.WriteLine("\nThese are the averages for each test.");

    Console.WriteLine("\n{0,-5} {1,20}", "Test", "Average");
    Console.WriteLine("------------------------------");

        foreach (List<int> i in dict.Values)
        {

          //Adds values in each list together

        }
    }

And this is my main program:

StudentInfo s = new StudentInfo();
            string name;
            string anoStudent;
            int grade;
            int numTests;
            int count = 1;
            int count2 = 1;

            do
            {
                Console.Write("\nWhat is student {0}s name?: ", count++);
                name = Console.ReadLine();

                Console.Write("\nHow many tests did they take? (Maximum of 8): ");
                numTests = int.Parse(Console.ReadLine());

                while (numTests > 8 || numTests == 0)
                {
                    Console.WriteLine("\nA student can only take up to 8 tests, and has to take at least one to be registered.");
                    Console.Write("Please enter again: ");
                    numTests = int.Parse(Console.ReadLine());
                }


                for (int x = 0; x < numTests; x++)
                {
                    Console.Write("What was their mark for test {0}: ", count2++);
                    grade = int.Parse(Console.ReadLine());

                    while (grade > 100 || grade < 0)
                    {
                        Console.WriteLine("\nA student can't have more than 100 percent or less than 0 percent on any given test.");
                        Console.Write("Please enter again: ");
                        grade = int.Parse(Console.ReadLine());

                    }

                    s.LoadGrades(name, grade); //load input into function

                }


                Console.Write("\nWould you like to add another student? (Yes or No): ");
                anoStudent = Console.ReadLine();

                numTests = 0; //reset variables
                count2 = 1;

            } while (anoStudent.ToLower() == "yes");

            s.DisplayGrades();
            s.StuAvg();
            s.TestAvg();
            Console.ReadKey(true);

I apologize for the length, but any help would be greatly appreciated :)

EDIT
I revised the non-LINQ method suggested by Nicholas that will allow it to calculate the averages of multiple lists, making sure to average only list locations that have been added together, so that unchanged locations are not affected. I also changed the original integer lists into double lists, for accuracy.

I thought you guys might want to see the finished code, so here's the function for it :)

 public void TestAvg() //Calculate the class average for each test
{
    List<int> counter = new List<int>(); //A list to hold the amount of students that took each test
    List<double> results = new List<double>(); //Create a new list to hold the final test averages
    double testAvg;

    Console.WriteLine("\nThis is the class average for each test.");

    Console.WriteLine("\n{0,-0} {1,20}", "Test", "Average");
    Console.WriteLine("--------------------------------------------------");

        foreach (List<double> l in dict.Values) //For every list in dict.Values
        {

            count2++; //Create a counter 

            for (int x = 0; x < l.Count(); x++ ) //Until x reaches the amount of elemets in l (list)
            {
                double value = l[x];   //Create a variable that will hold the value of l at location x                 

                if (x < results.Count) //if x is less than the amount of elements in results
                {
                    results[x] += value; //the value at x is equal to the value at x plus the variable value
                    counter[x] += 1;               
                }

                else
                {
                    results.Add(value); //Otherwise value is instead just added to the list, instead of being sumemd into the previous locations       
                    counter.Add(1);   
                }
            } 
        }

        for (int i = 0; i < results.Count; i++)
        {
            results[i] = results[i] / counter[i]; //Take the values at x in results and divide it by the amount of students that took each test (find the average)    
        }     

    foreach (double d in results) //For every double value in the list
    {                           
                testAvg = Math.Round(d, 2); //Round it to 2 decimal places
                Console.WriteLine("{0,-0} {1,20}%", count++ + 1, testAvg); //Output results                                                                             
    }          
}

If you have all the list added to your dictionary then you can do:

var query = dict.Values.Select(r => r.Select((number, i) => new { Index = i, Number = number }))
    .SelectMany(r => r)
    .GroupBy(r => r.Index)
    .Select(grp => new
    {
        Index = grp.Key,
        Value = grp.Sum(t => t.Number)

    });

Suppose you have Lists like :

List<int> list1 = new List<int>();
List<int> list2 = new List<int>();

list1.Add(2);
list1.Add(3);

list2.Add(1);
list2.Add(7);
Dictionary<string, List<int>> dict = new Dictionary<string, List<int>>();
dict.Add("1", list1);
dict.Add("2", list2);

then after executing LINQ query (first code snippet) you can do:

foreach (var item in query)
{
    Console.WriteLine("Index: {0}, Sum: {1}", item.Index, item.Value);
}

and you will get:

Index: 0, Sum: 3
Index: 1, Sum: 10

Here's a simple non-LINQ method for summing any number of lists in the manner you describe:

static List<int> SumOfLists( params List<int>[] lists )
{
  return SumOfLists( (IEnumerable<List<int>>) lists ) ;
}

static List<int> SumOfLists( IEnumerable<List<int>> lists )
{
  List<int> result = new List<int>() ;

  foreach ( List<int> list in lists )
  {

    for( int j = 0 ; j < list.Count ; ++j )
    {
      int value = list[j] ;

      if ( j < result.Count )
      {
        result[j] += value ;
      }
      else
      {
        result.Add( value ) ;
      }

    } // end for-j

  } // end for-each

  return result ;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM