I have made an exercise where I need to calculate the average per row of a .txt file. (see below)
Toa Narumi gradeA 10 8 7 4 6,5
Jean-François Le Clerk gradeB 5 4 7
Joe GradeC 10 10
I only want the numbers behind the name and grade. This is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Linq;
namespace RenoD_Oef_Strings
{
class Program
{
static void Main(string[] args)
{
// Variablen
StreamReader bestand = new StreamReader(@"F:\RenoD_Oef_Strings\Punten.txt");
string strRow; // String used to read every row of .txt file
double?[] dblPoints; // Double array used to store all values
List<string> strInput = new List<string>(); // String List used to store all data from .txt
// Code
while ((strRow = bestand.ReadLine()) != null) // Read row per row in .txt
{
strInput = strRow.Split(' ').ToList(); // Puts every word in the row in to the list
int intX = 0;
foreach(string strX in strInput) // Calculate how many strings are in the list
{
intX++;
}
dblPoints = new double?[intX]; // Calculate the max number of elements the double array can have
intX = 0;
foreach(var x in strInput) // Checks if elements in the list can be converted in to a double
{
try
{
double dblR = Convert.ToDouble(x); // If element can be converted in to a double, it will be stored in the double array
dblPoints[intX] = dblR;
intX++;
}
catch
{
intX++; // If element CAN NOT be converted in to a double, it will be still be stored in the double array but without any value
}
}
double dblAverage = 0; // Double used to save the total average of one row
intX = 0;
foreach(var k in dblPoints)
{
if (k.HasValue) // Elements without value will be ignored
{
dblAverage += Convert.ToDouble(k); // All double values will be added up
intX++; // Used to see how much double values there are to calculate average
}
}
dblAverage = Math.Round(dblAverage/intX, 2); // Calculate average + round up to two decimals
Console.WriteLine(dblAverage.ToString());
}
bestand.Close();
Console.ReadKey();
}
}
}
What I have done is
Read row per row .txt file
Put all elements of that row in a list
Calculate how many elements that the double array will need to store (same number of elements the list has), which I later on use to store all doubles of the list
Check if elements in the list can be converted in to a double array; If the element can be converted in to a double, it will be stored in the double array.
If element CAN NOT be converted in to a double, it will be still be stored in the double array but without any value.
- Only calculate the average of the elements in my double array that have values.
I have tested the code, and it works without any issue.
My question is, have I taken a good approach? What would you have done to make it more efficient?
I have tried searching in other threads for solutions. I have seen simular questions, but was unable to find any exactly the same as my exercise.
-
1\$\begingroup\$ Some tips: Dont mix german and english words. You use an object oriented language: Try to structure your code in functions. Then try to structure your code in classes. Dont mention the type of a variable in its name. This is old fashioned style. Dont write unnecessary code - use the appropriate methods of your language. If you explicitly want to implement already implemented features by yourself - use the "reinventing-the-wheel"-tag. Good luck and a lot of fun! \$\endgroup\$Dexter Thorn– Dexter Thorn2019年05月05日 15:57:27 +00:00Commented May 5, 2019 at 15:57
1 Answer 1
- Enclose the file reading in a
using
statement - Use
double.TryParse
or regex to parse the numbers - Use Linq extention method
Average()
to calculate average - The size of
strInput
isstrInput.Count
, no need for a loop
Hear is a simpler code:
using (StreamReader bestand = new StreamReader(@"F:\RenoD_Oef_Strings\Punten.txt"))
{
string strRow; // String used to read every row of .txt file
// Code
while ((strRow = bestand.ReadLine()) != null) // Read row per row in .txt
{
List<string> strInput = strRow.Split(' ').ToList(); // String List used to store all data from .txt
List<double> dblPoints = new List<double>(); // Double list used to store all values
foreach (var x in strInput) // Checks if elements in the list can be converted in to a double
{
if (double.TryParse(x, out double result))
{
dblPoints.Add(result);
}
}
double dblAverage = dblPoints.Average();
Console.WriteLine(dblAverage.ToString());
}
}
Console.ReadKey();
-
\$\begingroup\$ Thank you for your reply! It is indeed way simpeler. \$\endgroup\$Toa Narumi– Toa Narumi2019年05月05日 13:11:15 +00:00Commented May 5, 2019 at 13:11
-
\$\begingroup\$ Clean and does the trick. There is theoretical edge case where a grade could be NaN, which passes the TryParse check but the average would also be a NaN. If this could be a possibility, it would need to be accounted for. \$\endgroup\$Rick Davin– Rick Davin2019年05月06日 16:11:29 +00:00Commented May 6, 2019 at 16:11