I am trying to read from a file and save rows to a string or array Im not sure which would be more efficient.


string[] array = new string roomNumber[30];
string[] testScore;

I have the test file set up the following with random values;

studentID, classroomNumber (1-30), testScore (1-100);

SID001, 1, 90
SID002, 1, 88
SID003, 1, 99
SID004, 2, 78
SID005, 2, 100
SID006, 2, 98
ETC, to room number 30

I am trying to store the second row to string[] roomNumber; and third row to string[] testScore. Then get the total score for each classroomNumber 1, 2, 3, etc as well as the average for each classroomNumber. I have tried many different ways but not sure how to store seperate rows to a string then call it and use it when needed. Thank you for the help.

Dani AI

Generated

— if your only goal is "total and average per classroom", you don't need to keep every row in memory. is right that splitting each line into columns is the way to get room and score, but a simpler, memory-friendly pattern is to stream the file and maintain a running aggregation per room (sum and count). That keeps memory use proportional to number of rooms (30) instead of number of students.

The pattern: read each non-empty line, split on the comma, Trim() the tokens, parse room and score with TryParse, then update a dictionary keyed by room. After the file is processed compute average = (double)sum / count for each room. This avoids parallel lists and extra bookkeeping.

using System;
using System.Collections.Generic;
using System.IO;

class RoomAggregator
{
    static void Main()
    {
        string path = @"C:\Users\Desktop\test.txt";
        var rooms = new Dictionary<int, (int sum, int count)>();

        foreach (var line in File.ReadLines(path))
        {
            if (string.IsNullOrWhiteSpace(line)) continue;
            var parts = line.Split(',');
            if (parts.Length < 3) continue;

            if (!int.TryParse(parts[1].Trim(), out int room)) continue;
            if (!int.TryParse(parts[2].Trim(), out int score)) continue;

            if (rooms.TryGetValue(room, out var agg))
                rooms[room] = (agg.sum + score, agg.count + 1);
            else
                rooms[room] = (score, 1);
        }

        foreach (var kvp in rooms)
        {
            var total = kvp.Value.sum;
            var count = kvp.Value.count;
            Console.WriteLine("Room {0}: total={1}, average={2:F2}", kvp.Key, total, (double)total / count);
        }
    }
}

Troubleshooting notes: skip or detect a header row, use TryParse to avoid exceptions on bad data, Trim tokens to handle spaces, and switch to decimal if you need exact fractional averages. If you later need student-level queries keep a typed Student class and store per-room lists instead of aggregates.

Recommended Answers

All 7 Replies

I would suggest using a List<string> to store your rows.
You could also create a CLASS to hold your rows and store the rows in a List<CLASS> or a Dictionary<string, CLASS> where the key to the dictionary is the student ID.

If you're into creating classes, it will make keeping up with the scores to make an average easier.

static void Main(string[] args)
        {
            
        }//end main

        public String getFileContent(String filePath)
        {
            string FILENAME = @"C:\Users\Desktop\test.txt";
            FileStream inFile = new FileStream(FILENAME, FileMode.Open, FileAccess.Read);
            StreamReader reader = new StreamReader(inFile);

        }//end getFileContent

        public double getSumOfNumbers(List<double> numbers)
        {
        }//end getSumeOfNumbers

        public double getAverageNumbers(List<double> numbers)
        {
        }//end getAverageOfNumbers

        public List<double> getEveryThreeValues(String source)
        {
        }//end getEveryThreeValues
    }

Would something like this work? Im not even sure if I am reading the file correctly though.

Well, you getFileContent method is set to return 1 string.
Let's look at it a different way:

If you wanted ALL of the rows from the file into a list of strings, you could do this:

using System.Collections.Generic;
using System.IO;

namespace DW_393702
{
   class CDW_393702
   {
      static void Main(string[] args)
      {
         StreamReader fileIn = new StreamReader("../../TextFile1.txt");
         //
         List<string> lst_strData = new List<string>();
         while (!fileIn.EndOfStream)
         {
            lst_strData.Add(fileIn.ReadLine());
         }
         //
         fileIn.Close();
      }
   }
}

With the data loaded in the list, you would still need to access the individual rows (no big deal) and get the usable data from them, right?

You could use the string .Split() method to get data from the individual strings.
You could also use more than one list or array and split the strings as they are read and count them as they are read IF nothing else is to happen to the records.

Yea nothing else is happening with the records. If I was to count and split them as they are read would I use a for loop?

for(i = 0; i <= 30; i++) //to get the testScores for each roomNumber

then how would I assign the three testScores to the room number so I can do the math? Or am I making it harder than it should be?

I simply want to read the second and third row and add the testScore to get total and the average for each roomNumber

So, if you were to use 3 arrays (or lists), you could split the incoming string by the comma (and the space) and set the StringSplitOptions to remove empty entries.

At that point, the .Split() method would return to you three columns; the first of which would be the Student ID. The second (could be converted to an int) would be the room number. The third (converted to an int) would be the grades.

[Just a technique]
You could technically (simultaneously) loop through the room list and the grad list and add up grades based on rooms.

[Just a technique]
You could technically (simultaneously) loop through the room list and the grad list and add up grades based on rooms.

Yes this is what I am trying to do...Not sure how to go about it though..

so would I set up a string array the following?? Or should I make a string array for roomNumber and testScore as well?

static void Main(string[] args)
        {
            string[] arr1 = new string[] { "studentID", "roomNumber", "testScore" };
            int sum = 0;
            int average = 0;

            StreamReader fileIn = new StreamReader(@"C:\Users\Desktop\test.txt");

            List<String> lst_strData = new List<string>();
            while (!fileIn.EndOfStream)
            {
                lst_strData.Add(fileIn.ReadLine());
                
            }//end while
            fileIn.Close();
        }//end main

My vision has it like this:

using System;
using System.Collections.Generic;
using System.IO;

namespace DW_393702
{
   class CDW_393702
   {
      static void Main(string[] args)
      {
         List<string> lst_strStudents = new List<string>();
         List<string> lst_strRooms = new List<string>();
         List<int> lst_intGrades = new List<int>();

         string[] arr_strData = { };
         StreamReader fileIn = new StreamReader("../../TextFile1.txt");
         while (!fileIn.EndOfStream)
         {
            // split the incoming data into columns
            arr_strData = fileIn.ReadLine().Split(", ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

            lst_strStudents.Add(arr_strData[0]);
            lst_strRooms.Add(arr_strData[1]);
            lst_intGrades.Add(int.Parse(arr_strData[2]));
         }

         fileIn.Close();

         /* at this point, the lists are all the same size, so you can
          * use one counter to go through the lists
          * You will need something to tell you how many students per room
          * You will need something to tell you how many actual distinct rooms
          */
      }
   }
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.