Skip to content

Update Sum columns #46542

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions docs/csharp/linq/how-to-query-files-and-directories.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,4 @@ The following text shows how to use the <xref:System.String.Split%2A> method to

:::code language="csharp" source="./snippets/HowToFilesAndDirectories/SumColumns.cs" id="SumColumns":::

If your file is a tab-separated file, just update the argument in the `Split` method to `\t`.

If your file is a tab-separated file, just update the argument in the `SumColumns.ProcessColumns` method to `\t`.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

Console.WriteLine();
Console.WriteLine("Sum Spreadsheet columns");
SumColumns.SumCSVColumns("scores.csv");
SumColumns.ProcessColumns("scores.csv", ",");

static void FindFilesByExtension()
{
Expand Down
146 changes: 44 additions & 102 deletions docs/csharp/linq/snippets/HowToFilesAndDirectories/SumColumns.cs
Original file line number Diff line number Diff line change
@@ -1,117 +1,59 @@
namespace HowToFilesAndDirectories;

// <SumColumns>
public class SumColumns
public static class SumColumns
{
public static void SumCSVColumns(string fileName)
public static void ProcessColumns(string filePath, string seperator)
{
string[] lines = File.ReadAllLines(fileName);

// Specifies the column to compute.
int exam = 3;

// Spreadsheet format:
// Student ID Exam#1 Exam#2 Exam#3 Exam#4
// 111, 97, 92, 81, 60

// Add one to exam to skip over the first column,
// which holds the student ID.
SingleColumn(lines, exam + 1);
Console.WriteLine();
MultiColumns(lines);
}

static void SingleColumn(IEnumerable<string> strs, int examNum)
{
Console.WriteLine("Single Column Query:");

// Parameter examNum specifies the column to
// run the calculations on. This value could be
// passed in dynamically at run time.

// Variable columnQuery is an IEnumerable<int>.
// The following query performs two steps:
// 1) use Split to break each row (a string) into an array
// of strings,
// 2) convert the element at position examNum to an int
// and select it.
var columnQuery = from line in strs
let elements = line.Split(',')
select Convert.ToInt32(elements[examNum]);

// Execute the query and cache the results to improve
// performance. This is helpful only with very large files.
var results = columnQuery.ToList();

// Perform aggregate calculations Average, Max, and
// Min on the column specified by examNum.
double average = results.Average();
int max = results.Max();
int min = results.Min();

Console.WriteLine($"Exam #{examNum}: Average:{average:##.##} High Score:{max} Low Score:{min}");
// Divide each exam into a group
var exams = from line in MatrixFrom(filePath, seperator)
from score in line

// Identify the column number
let colNumber = Array.FindIndex(line, t => ReferenceEquals(score, t))

// The first column is the student ID, not the exam score
// so it needs to be excluded
where colNumber > 0

// Convert the score from string to int
// Group by column number, i.e. one group per exam
group double.Parse(score) by colNumber into g
select new
{
Title = $"Exam#{g.Key}",
Min = g.Min(),
Max = g.Max(),
Avg = Math.Round(g.Average(), 2),
Total = g.Sum()
};

foreach (var exam in exams)
{
Console.WriteLine($"{exam.Title}\t"
+ $"Average:{exam.Avg,6}\t"
+ $"High Score:{exam.Max,3}\t"
+ $"Low Score:{exam.Min,3}\t"
+ $"Total:{exam.Total,5}");
}
}

static void MultiColumns(IEnumerable<string> strs)
// Transform the file content to an IEnumerable of string arrays
// like a matrix
private static IEnumerable<string[]> MatrixFrom(string filePath, string seperator)
{
Console.WriteLine("Multi Column Query:");

// Create a query, multiColQuery. Explicit typing is used
// to make clear that, when executed, multiColQuery produces
// nested sequences. However, you get the same results by
// using 'var'.
using StreamReader reader = File.OpenText(filePath);

// The multiColQuery query performs the following steps:
// 1) use Split to break each row (a string) into an array
// of strings,
// 2) use Skip to skip the "Student ID" column, and store the
// rest of the row in scores.
// 3) convert each score in the current row from a string to
// an int, and select that entire sequence as one row
// in the results.
var multiColQuery = from line in strs
let elements = line.Split(',')
let scores = elements.Skip(1)
select (from str in scores
select Convert.ToInt32(str));

// Execute the query and cache the results to improve
// performance.
// ToArray could be used instead of ToList.
var results = multiColQuery.ToList();

// Find out how many columns you have in results.
int columnCount = results[0].Count();

// Perform aggregate calculations Average, Max, and
// Min on each column.
// Perform one iteration of the loop for each column
// of scores.
// You can use a for loop instead of a foreach loop
// because you already executed the multiColQuery
// query by calling ToList.
for (int column = 0; column < columnCount; column++)
for (string? line = reader.ReadLine(); line is not null; line = reader.ReadLine())
{
var results2 = from row in results
select row.ElementAt(column);
double average = results2.Average();
int max = results2.Max();
int min = results2.Min();

// Add one to column because the first exam is Exam #1,
// not Exam #0.
Console.WriteLine($"Exam #{column + 1} Average: {average:##.##} High Score: {max} Low Score: {min}");
yield return line.Split(seperator, StringSplitOptions.TrimEntries);
}
}
}
/* Output:
Single Column Query:
Exam #4: Average:76.92 High Score:94 Low Score:39

Multi Column Query:
Exam #1 Average: 86.08 High Score: 99 Low Score: 35
Exam #2 Average: 86.42 High Score: 94 Low Score: 72
Exam #3 Average: 84.75 High Score: 91 Low Score: 65
Exam #4 Average: 76.92 High Score: 94 Low Score: 39
*/
// Output:
// Exam#1 Average: 86.08 High Score: 99 Low Score: 35 Total: 1033
// Exam#2 Average: 86.42 High Score: 94 Low Score: 72 Total: 1037
// Exam#3 Average: 84.75 High Score: 91 Low Score: 65 Total: 1017
// Exam#4 Average: 76.92 High Score: 94 Low Score: 39 Total: 923
// </SumColumns>