Skip to content

Commit 4d58413

Browse files
Update Sum columns (#46542)
* Update SumColumns.cs * Update Program.cs * Update how-to-query-files-and-directories.md * Update how-to-query-files-and-directories.md --------- Co-authored-by: Bill Wagner <[email protected]>
1 parent 2cdbe9b commit 4d58413

File tree

3 files changed

+46
-105
lines changed

3 files changed

+46
-105
lines changed

docs/csharp/linq/how-to-query-files-and-directories.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,5 +129,4 @@ The following text shows how to use the <xref:System.String.Split%2A> method to
129129

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

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

docs/csharp/linq/snippets/HowToFilesAndDirectories/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
Console.WriteLine();
3434
Console.WriteLine("Sum Spreadsheet columns");
35-
SumColumns.SumCSVColumns("scores.csv");
35+
SumColumns.ProcessColumns("scores.csv", ",");
3636

3737
static void FindFilesByExtension()
3838
{
Lines changed: 44 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,59 @@
11
namespace HowToFilesAndDirectories;
22

33
// <SumColumns>
4-
public class SumColumns
4+
public static class SumColumns
55
{
6-
public static void SumCSVColumns(string fileName)
6+
public static void ProcessColumns(string filePath, string seperator)
77
{
8-
string[] lines = File.ReadAllLines(fileName);
9-
10-
// Specifies the column to compute.
11-
int exam = 3;
12-
13-
// Spreadsheet format:
14-
// Student ID Exam#1 Exam#2 Exam#3 Exam#4
15-
// 111, 97, 92, 81, 60
16-
17-
// Add one to exam to skip over the first column,
18-
// which holds the student ID.
19-
SingleColumn(lines, exam + 1);
20-
Console.WriteLine();
21-
MultiColumns(lines);
22-
}
23-
24-
static void SingleColumn(IEnumerable<string> strs, int examNum)
25-
{
26-
Console.WriteLine("Single Column Query:");
27-
28-
// Parameter examNum specifies the column to
29-
// run the calculations on. This value could be
30-
// passed in dynamically at run time.
31-
32-
// Variable columnQuery is an IEnumerable<int>.
33-
// The following query performs two steps:
34-
// 1) use Split to break each row (a string) into an array
35-
// of strings,
36-
// 2) convert the element at position examNum to an int
37-
// and select it.
38-
var columnQuery = from line in strs
39-
let elements = line.Split(',')
40-
select Convert.ToInt32(elements[examNum]);
41-
42-
// Execute the query and cache the results to improve
43-
// performance. This is helpful only with very large files.
44-
var results = columnQuery.ToList();
45-
46-
// Perform aggregate calculations Average, Max, and
47-
// Min on the column specified by examNum.
48-
double average = results.Average();
49-
int max = results.Max();
50-
int min = results.Min();
51-
52-
Console.WriteLine($"Exam #{examNum}: Average:{average:##.##} High Score:{max} Low Score:{min}");
8+
// Divide each exam into a group
9+
var exams = from line in MatrixFrom(filePath, seperator)
10+
from score in line
11+
12+
// Identify the column number
13+
let colNumber = Array.FindIndex(line, t => ReferenceEquals(score, t))
14+
15+
// The first column is the student ID, not the exam score
16+
// so it needs to be excluded
17+
where colNumber > 0
18+
19+
// Convert the score from string to int
20+
// Group by column number, i.e. one group per exam
21+
group double.Parse(score) by colNumber into g
22+
select new
23+
{
24+
Title = $"Exam#{g.Key}",
25+
Min = g.Min(),
26+
Max = g.Max(),
27+
Avg = Math.Round(g.Average(), 2),
28+
Total = g.Sum()
29+
};
30+
31+
foreach (var exam in exams)
32+
{
33+
Console.WriteLine($"{exam.Title}\t"
34+
+ $"Average:{exam.Avg,6}\t"
35+
+ $"High Score:{exam.Max,3}\t"
36+
+ $"Low Score:{exam.Min,3}\t"
37+
+ $"Total:{exam.Total,5}");
38+
}
5339
}
5440

55-
static void MultiColumns(IEnumerable<string> strs)
41+
// Transform the file content to an IEnumerable of string arrays
42+
// like a matrix
43+
private static IEnumerable<string[]> MatrixFrom(string filePath, string seperator)
5644
{
57-
Console.WriteLine("Multi Column Query:");
58-
59-
// Create a query, multiColQuery. Explicit typing is used
60-
// to make clear that, when executed, multiColQuery produces
61-
// nested sequences. However, you get the same results by
62-
// using 'var'.
45+
using StreamReader reader = File.OpenText(filePath);
6346

64-
// The multiColQuery query performs the following steps:
65-
// 1) use Split to break each row (a string) into an array
66-
// of strings,
67-
// 2) use Skip to skip the "Student ID" column, and store the
68-
// rest of the row in scores.
69-
// 3) convert each score in the current row from a string to
70-
// an int, and select that entire sequence as one row
71-
// in the results.
72-
var multiColQuery = from line in strs
73-
let elements = line.Split(',')
74-
let scores = elements.Skip(1)
75-
select (from str in scores
76-
select Convert.ToInt32(str));
77-
78-
// Execute the query and cache the results to improve
79-
// performance.
80-
// ToArray could be used instead of ToList.
81-
var results = multiColQuery.ToList();
82-
83-
// Find out how many columns you have in results.
84-
int columnCount = results[0].Count();
85-
86-
// Perform aggregate calculations Average, Max, and
87-
// Min on each column.
88-
// Perform one iteration of the loop for each column
89-
// of scores.
90-
// You can use a for loop instead of a foreach loop
91-
// because you already executed the multiColQuery
92-
// query by calling ToList.
93-
for (int column = 0; column < columnCount; column++)
47+
for (string? line = reader.ReadLine(); line is not null; line = reader.ReadLine())
9448
{
95-
var results2 = from row in results
96-
select row.ElementAt(column);
97-
double average = results2.Average();
98-
int max = results2.Max();
99-
int min = results2.Min();
100-
101-
// Add one to column because the first exam is Exam #1,
102-
// not Exam #0.
103-
Console.WriteLine($"Exam #{column + 1} Average: {average:##.##} High Score: {max} Low Score: {min}");
49+
yield return line.Split(seperator, StringSplitOptions.TrimEntries);
10450
}
10551
}
10652
}
107-
/* Output:
108-
Single Column Query:
109-
Exam #4: Average:76.92 High Score:94 Low Score:39
11053

111-
Multi Column Query:
112-
Exam #1 Average: 86.08 High Score: 99 Low Score: 35
113-
Exam #2 Average: 86.42 High Score: 94 Low Score: 72
114-
Exam #3 Average: 84.75 High Score: 91 Low Score: 65
115-
Exam #4 Average: 76.92 High Score: 94 Low Score: 39
116-
*/
54+
// Output:
55+
// Exam#1 Average: 86.08 High Score: 99 Low Score: 35 Total: 1033
56+
// Exam#2 Average: 86.42 High Score: 94 Low Score: 72 Total: 1037
57+
// Exam#3 Average: 84.75 High Score: 91 Low Score: 65 Total: 1017
58+
// Exam#4 Average: 76.92 High Score: 94 Low Score: 39 Total: 923
11759
// </SumColumns>

0 commit comments

Comments
 (0)