0

I am trying to create a program which takes data from a text file and uses that text to derive grades for a student. I have 4 students I need to enter, that are stored in a text file, that are in rows as such:

ID || first name || last name || Grades

01999911 || Bill || Gates || 27,30,56,60.

I am struggling with capturing the grades of the students, which are in the order of 27 (earned points),30 (possible points),56 (earned points),60 (possible points). That string extends for 10 different values for earned points, and 10 values for possible points, in the format of earned points followed by possible points, separated by a coma. After that, I have to take those data points and find the average grade for the student.

I was wondering if anyone would be able to point me in the direction of where I could learn how to code that in, or provide some example code for help. Thanks for any responses.

Preet
  • 984
  • 2
  • 14
  • 34
Toby Z
  • 31
  • 1
  • 5
  • What code so you have so far? It sounds like you only need help with the final column of data, is that right? Is the full-stop after the 60 a typo or intentional? Does 'grade' refer to earned/possible? – Richardissimo May 16 '18 at 05:05
  • I am so far just writing the code for populating the list and creating the getters and setters for the data. I am more of wondering how I am able to separate each variable I need, and tying that data to the student ID. – Toby Z May 16 '18 at 05:08
  • I see from your [new question](https://stackoverflow.com/questions/50364778/index-was-outside-the-bounds-of-the-array) that you decided to go with commas to separate *everything*. If you look at how my answer processes the `remainder`, including checking what's in there, then your IndexOutOfRangeException problem will go away. And it will highlight which line has the faulty data. – Richardissimo May 17 '18 at 05:25
  • P.S. You can mark an answer as the accepted answer by pressing the 'tick' to the left of that answer. – Richardissimo May 17 '18 at 05:26
  • Also the approach in that question uses a pair of arrays rather than the object oriented approach shown here. I really think you should try this approach. Or if you want to stick with an "all commas" approach then add a comment to my answer below, and I will rework my answer below to answer your other question. – Richardissimo May 17 '18 at 05:40

1 Answers1

1

I'm assuming that the full-stop after the 60 in the question is a typo. I'm assuming 'grade' refers to earned/possible.

Since you've said you are currently writing the code to populate the list, I would suggest using the tab character rather than the two pipe character separator. This will make the file a TSV file, and makes the code slightly easier to write. (The tab character is represented by \t in source code, either in a string, or as a character: '\t'.) If you're writing the file yourself, it would help to keep the earned & possible values together using a different separator; for example 27,30;56,60;45,70(etc). This makes it easier to separate; but I'll show solutions for both.

    public class Result
    {
        // This constructor is used by the "different separator for Earned and Possible" approach.
        // Remove this and the default constructor if you don't want to go that way.
        public Result(string line)
        {
            var parts = line.Split(',');
            if (parts.Length != 2)
            {
                throw new ArgumentException($"Result had {parts.Length} parts: '{line}'");
            }

            EarnedPoints = int.Parse(parts[0]);
            PossiblePoints = int.Parse(parts[1]);
        }

        public Result()
        {
        }

        // Remove this constructor if you go for the approach above.
        public Result(int earnedPoints, int possiblePoints)
        {
            EarnedPoints = earnedPoints;
            PossiblePoints = possiblePoints;
        }

        public int EarnedPoints { get; }
        public int PossiblePoints { get; }
        public double Grade => (double)EarnedPoints / PossiblePoints;
        public string GradeAsPercentage => $"{Grade:P2}";
    }

    public class Student
    {
        public Student(string line)
        {
            var parts = line.Split(new[] { "||" }, StringSplitOptions.None);
            // Could use this instead if you go for TSV:   var parts = line.Split('\t');

            if (parts.Length != 4)
            {
                throw new ArgumentException($"Student had {parts.Length} parts: '{line}'");
            }

            Id = parts[0];
            Forenames = parts[1];
            Surname = parts[2];

            string remainder = parts[3];

            // This is how simple it would be if you used a different separator to group the Earned and Possible together
            //        Results = remainder.Split(';').Select(result => new Result(result)).ToList();
            // Below is an approach where commas are used for everything...
            Results = new List<Result>();
            var items = remainder.Split(',');
            if (items.Length % 2 == 1)
            {
                throw new ArgumentException($"Odd number of parts in the result: '{line}'");
            }

            int offset = 0;
            while (offset < items.Length)
            {
                int earnedPoints = int.Parse(items[offset++]);
                int possiblePoints = int.Parse(items[offset++]);
                Results.Add(new Result(earnedPoints, possiblePoints));
            }
        }

        public string Id { get; } // Could make this an 'int', in which case use "int.Parse(parts[0])" when setting it, above
        public string Forenames { get; }
        public string Surname { get; }
        public IList<Result> Results { get; }
        public double AverageGrade => Results.Average(r => r.Grade);
        public string AverageGradeAsPercentage => $"{AverageGrade:P2}";
    }

then you could just do this to read in the whole file...

        var students = File.ReadLines(yourFileName).Skip(1).Select(l => new Student(l));

Slight caution: I've gotta go, so rushed a few bits, but hopefully it all works.

Richardissimo
  • 5,596
  • 2
  • 18
  • 36