I am fairly new to programming and I am having difficulty modulating the following code.
The program reads a file, selects certain requirements, and displays them. I have tried to use passing arrays as arguments or functions as indicated in my textbook. I have been using examples such as int getAges(int array[], integer)
.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Project_2_practice
{
class Program
{
static void Main(string[] args)
{
//Parsing data into memory
string content;
using (StreamReader reader = new StreamReader(File.Open("Data.txt", FileMode.Open)))
{
content = reader.ReadToEnd();
}
string[] rows = content.Split('\n'); //Each row is on a new line
string[][] table = new string[rows.Length][];
for (int i = 0; i < rows.Length; table[i] = rows[i].Split(','), i++) ;
//selecting information
int[] districts = new int[rows.Length];
int[] ages = new int[rows.Length];
for (int i = 0; i < rows.Length; i++)
{
districts[i] = int.Parse(table[i][3]);
ages[i] = int.Parse(table[i][0]);
}
//Analyzing selected information
foreach (int district in districts.Distinct().OrderBy(x => x))
Console.WriteLine("District {0} has {1} resident(s)", district, districts.Count(x => x == district));
Console.WriteLine("Ages 0-18 : {0} resident(s)", ages.Count(x => x < 18));
Console.WriteLine("Ages 18-30 : {0} resident(s)", ages.Count(x => x >= 18 && x <= 30));
Console.WriteLine("Ages 31-45 : {0} resident(s)", ages.Count(x => x >= 31 && x <= 45));
Console.WriteLine("Ages 46-64 : {0} resident(s)", ages.Count(x => x >= 46 && x <= 64));
Console.WriteLine("Ages >=65 : {0} resident(s)", ages.Count(x => x >= 65));
}
}
}
2 Answers 2
Here's how I would do it.
Update: I included a description of my code this time based on comments.
First, reading a file into a variable so that each line of the file is its own element in an array is super easy with File.ReadAllLines(...). But I don't feel like using a variable for that is necessary here, so I immediately start using the array by using the Select(...) method. I'm using Select here to create an anonymous type (That's the return new { ... } part).
var data = File.ReadAllLines(@"c:\temp\data.txt").Select (f =>
{
var split = f.Split(',');
return new {
Age = int.Parse(split[0]),
District = split[3]
};
});
At this point, I've got a type-safe collection of "data" that I can work with. That's important, and very useful. For example..
var byDistrict = data.GroupBy (d => d.District);
In the line above, I've grouped the data by District. Grouping is, in my opinion, almost always better than using Distinct.
The rest of the code is very similar to your original code, except my code avoids the need to have the age reports within a loop.
foreach (var district in byDistrict)
{
Console.WriteLine("District {0} has {1} resident(s)", district.Key, district.Count());
}
Console.WriteLine("Ages 0-18 : {0} resident(s)", data.Count(x => x.Age < 18));
Console.WriteLine("Ages 18-30 : {0} resident(s)", data.Count(x => x.Age >= 18 && x.Age <= 30));
Console.WriteLine("Ages 31-45 : {0} resident(s)", data.Count(x => x.Age >= 31 && x.Age <= 45));
Console.WriteLine("Ages 46-64 : {0} resident(s)", data.Count(x => x.Age >= 46 && x.Age <= 64));
Console.WriteLine("Ages >=65 : {0} resident(s)", data.Count(x => x.Age >= 65));
-
\$\begingroup\$ would you please explain your code? Code Only answers are frowned upon on Code Review. \$\endgroup\$Malachi– Malachi2013年11月06日 15:55:44 +00:00Commented Nov 6, 2013 at 15:55
-
\$\begingroup\$ Sorry. Fairly new to Code Review. But I really love this site. \$\endgroup\$Alex Dresko– Alex Dresko2013年11月06日 16:06:04 +00:00Commented Nov 6, 2013 at 16:06
-
\$\begingroup\$ it's all good, thank you for editing your answer. +1 \$\endgroup\$Malachi– Malachi2013年11月06日 16:32:45 +00:00Commented Nov 6, 2013 at 16:32
I feel as though you are looking at how to really understand the code and how to separate it out into functions and still have all the variables working and all that. I rewrote it a bit to show how to use different functions with and without return values, with variables passed in, using global variables, and passing in variables by reference. Take a look.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Project_2_practice
{
class Program
{
static string[][] table;
static void Main(string[] args)
{
//Parsing data into memory
string[] rows = ReadLines("Data.txt");
table = new string[rows.Length][];
PopulateTable(rows);
//selecting information
int[] districts = new int[rows.Length];
int[] ages = new int[rows.Length];
PopulateArrays(ref districts, ref ages, rows.Length);
//Analyzing selected information
DisplayResults(districts, ages);
}
/// <summary>
/// Read file into memory
/// </summary>
/// <param name="file">string filepath</param>
/// <returns>array of lines in file</returns>
private static string[] ReadLines(string file)
{
return File.ReadAllLines(file);
}
/// <summary>
/// Populates a table with split values from the string
/// </summary>
/// <param name="rows">array of strings to split</param>
private static void PopulateTable(string[] rows)
{
for (int i = 0; i < rows.Length; table[i] = rows[i].Split(','), i++) ;
}
/// <summary>
/// Populates 2 arrays by reference with values from the table variable
/// </summary>
/// <param name="districts">int array</param>
/// <param name="ages">int array</param>
/// <param name="length">int length of table</param>
private static void PopulateArrays(ref int[] districts, ref int[] ages, int length)
{
for (int i = 0; i < length; i++)
{
districts[i] = int.Parse(table[i][3]);
ages[i] = int.Parse(table[i][0]);
}
}
/// <summary>
/// Writes values to console for displaying results
/// </summary>
/// <param name="districts">int array of districts</param>
/// <param name="ages">int array of ages</param>
private static void DisplayResults(int[] districts, int[] ages)
{
foreach (int district in districts.Distinct().OrderBy(x => x))
{
Console.WriteLine("District {0} has {1} resident(s)", district, districts.Count(x => x == district));
}
Console.WriteLine("Ages 0-18 : {0} resident(s)", ages.Count(x => x < 18));
Console.WriteLine("Ages 18-30 : {0} resident(s)", ages.Count(x => x >= 18 && x <= 30));
Console.WriteLine("Ages 31-45 : {0} resident(s)", ages.Count(x => x >= 31 && x <= 45));
Console.WriteLine("Ages 46-64 : {0} resident(s)", ages.Count(x => x >= 46 && x <= 64));
Console.WriteLine("Ages >=65 : {0} resident(s)", ages.Count(x => x >= 65));
}
}
}
-
\$\begingroup\$ thank you very much for this insight! this is exactly what I wanted to see if it was possible, however your code doesn't compile, it seems that the errors marked in visual studio are that static string[] contentLines; static string[][] table; are not used \$\endgroup\$hec– hec2013年11月06日 15:15:48 +00:00Commented Nov 6, 2013 at 15:15
-
\$\begingroup\$ You are right, I am going to edit my answer to fix those. I erroneously created a local variable named table as well as the global one so that caused the code to fail. Also, I just removed the contentLines var as it's not needed. \$\endgroup\$Kemo Sabe– Kemo Sabe2013年11月06日 15:24:04 +00:00Commented Nov 6, 2013 at 15:24
-
1\$\begingroup\$ thank you I see how everything comes together, this is pretty interesting. Thanks for making me understand Kemo Sabe! \$\endgroup\$hec– hec2013年11月06日 15:47:57 +00:00Commented Nov 6, 2013 at 15:47
-
1\$\begingroup\$ Glad to help :) \$\endgroup\$Kemo Sabe– Kemo Sabe2013年11月06日 15:48:37 +00:00Commented Nov 6, 2013 at 15:48