HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Obtaining different weather forecasts from the Environment Canada website

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
obtainingwebsitethecanadaenvironmentdifferentforecastsfromweather

Problem

Here is the code I use to get the different weather forecasts from the Environment Canada website:

```
public static void Main()
{
string url = "http://dd.weather.gc.ca/nowcasting/matrices/SCRIBE.NWCSTG." + DateTime.Now.ToString("MM.dd.HH") + "Z.n.Z";
string allStations = Decompress.zDecompress(url).ToString();
string temp = allStations.Substring(allStations.IndexOf("STN: CYYC"));
string weatherReports = temp.Substring(0, temp.IndexOf("+\n."));
string[] lines = weatherReports.Split(new string[] { "\n" }, StringSplitOptions.None);
Station s = new Station();
foreach (string line in lines)
{
if (line.IndexOf("-") != 0 && line.IndexOf("STN") != 0 && line.IndexOf("DATE") != 0)
{
Weather w = new Weather();
string[] properties = line.Split('|');
for (int i = 0; i < properties.Length; i++)
{
properties[i] = properties[i].Trim();
if (properties[i] == ""){
properties[i] = "0";
}
}
w.SkyCover = int.Parse(properties[1].Trim());
w.Ceiling = int.Parse(properties[2].Trim());
w.Pcpn1 = properties[3].Trim();
w.Pop1 = int.Parse(properties[4].Trim());
w.Pcpn2 = properties[5].Trim();
w.Pop2 = int.Parse(properties[6].Trim());
w.Pcpn3 = properties[7].Trim();
w.Pop3 = int.Parse(properties[8].Trim());
w.Pop = int.Parse(properties[9].Trim());
w.PcpnQuantity = double.Parse(properties[10].Trim());
w.PcpnType = properties[11].Trim();
w.Temperature = double.Parse(properties[12].Trim());
w.DewPoint = double.Parse(properties[13].Trim());
w.WindDirection = int.Parse(properties[14].Trim());
w.WindSpeed = int.Parse(properties[15].Trim());
w.GustSpeed = int.Parse(properties[16].Trim());
w.Visibility = double.Parse(properties[17].Trim());
w.VisOb

Solution

Single responsibility

Each method should have one clear responsibility. Your code is doing a lot of different things all in one method - the entry point of the application no less. Add in some additional methods to make things clearer:

For example:

private static string GetFullWeatherReport()
{
    string url = string.Format("http://dd.weather.gc.ca/nowcasting/matrices/SCRIBE.NWCSTG.{0:MM.dd.HH}Z.n.Z", DateTime.Now);
    return Decompress.zDecompress(url).ToString();
}

private static IEnumerable GetStationReports()
{
    // There appears to be a line with a only a dot between stations
    return GetFullWeatherReport().Split(new[] { "\n.\n" }, StringSplitOptions.RemoveEmptyEntries); 
}


That means you can now replace the first few lines of Main:

public static void Main()
{
     IEnumerable stationReports = GetStationReports();
     var cyycReport = stationReports.FirstOrDefault(r => r.StartsWith("STN: CYYC"));
     foreach (var line in GetDataRows(cyycReport))
     {
         // ParseWeatherReport();
     }
} 

private static IEnumerable GetDataRows(string weatherReport)
{
    return weatherReport.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries).Where(IsDataRow);
}

private static bool IsDataRow(string reportLine)
{
    return !reportLine.StartsWith("-") && !reportLine.StartsWith("DATE") && !reportLine.StartsWith("STN");
}


Keep going through the code and extracting methods so that you can read Main like a book - I think a good rule of thumb is whether or not a non-programmer has a decent chance of figuring out what's happening.
LINQ

I introduced a new concept or two into your code, one of which was LINQ. I can't explain the full magic of LINQ adequately so I enourage you to go and do some reading on it. The central concept is IEnumerable and a set of extension methods like Select, Where and FirstOrDefault.

For example:

string[] properties = line.Split('|');
for (int i = 0; i < properties.Length; i++)
{
    properties[i] = properties[i].Trim();
    if (properties[i] == ""){
        properties[i] = "0";
    }
}


Could become:

string[] lines = line.Split('|').Select(s => s.Trim()).Select(s => string.IsNullOrEmpty(s) ? "0" : s).ToArray();


var

If the type of an assignment is obvious, I prefer to use var e.g.

var welcomeMessage = "Hello!";


vs

string welcomeMessage = "Hello!";


I hope that's a useful start - all code typed directly into browser so apologies if it doesn't compile!

Code Snippets

private static string GetFullWeatherReport()
{
    string url = string.Format("http://dd.weather.gc.ca/nowcasting/matrices/SCRIBE.NWCSTG.{0:MM.dd.HH}Z.n.Z", DateTime.Now);
    return Decompress.zDecompress(url).ToString();
}

private static IEnumerable<string> GetStationReports()
{
    // There appears to be a line with a only a dot between stations
    return GetFullWeatherReport().Split(new[] { "\n.\n" }, StringSplitOptions.RemoveEmptyEntries); 
}
public static void Main()
{
     IEnumerable<string> stationReports = GetStationReports();
     var cyycReport = stationReports.FirstOrDefault(r => r.StartsWith("STN: CYYC"));
     foreach (var line in GetDataRows(cyycReport))
     {
         // ParseWeatherReport();
     }
} 

private static IEnumerable<string> GetDataRows(string weatherReport)
{
    return weatherReport.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries).Where(IsDataRow);
}

private static bool IsDataRow(string reportLine)
{
    return !reportLine.StartsWith("-") && !reportLine.StartsWith("DATE") && !reportLine.StartsWith("STN");
}
string[] properties = line.Split('|');
for (int i = 0; i < properties.Length; i++)
{
    properties[i] = properties[i].Trim();
    if (properties[i] == ""){
        properties[i] = "0";
    }
}
string[] lines = line.Split('|').Select(s => s.Trim()).Select(s => string.IsNullOrEmpty(s) ? "0" : s).ToArray();
var welcomeMessage = "Hello!";

Context

StackExchange Code Review Q#99131, answer score: 6

Revisions (0)

No revisions yet.