4
\$\begingroup\$

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.VisObstacleType = properties[18].Trim();
           s.Reports.Add(w);
}}}

And here is what the string looks like after my substrings:

STN: CYYC    |SKY|CIG|        PRECIPITATION        |POP|   ACC  |    TEMP   |    WIND   |  VIS   |
\nDATE      HR |/10|   |PCPN1|POP|PCPN2|POP|PCPN3|POP|   | Qp | Tp|  T  |  Td | DD| VV|GST|(SM) |TP|
\n-------------+---+---+-----+---+-----+---+-----+---+---+----+---+-----+-----+---+---+---+-----+--+
\n20150805 0600|  8|140| -RW |100|     |  0|     |  0| 60| 0.0|   | 13.0| 10.0|  0|  0|   |15.00|  |
\n20150805 0700|  8| 92|     |  0|     |  0|     |  0|  0| 0.0|   | 13.0| 11.0|290|  9|   |10.00|  |
\n20150805 0800|  9| 82|     |  0|     |  0|     |  0|  0| 0.0|   | 13.0| 11.0|  0|  0|   |15.00|  |
\n-------------+---+---+-----+---+-----+---+-----+---+---+----+---+-----+-----+---+---+---+-----+--+
\n20150805 0900|  6| 91|     |  0|     |  0|     |  0|  0| 0.0|   | 13.0| 10.0|  0|  0|   |15.00|  |
\n20150805 1000|  8| 84|     |  0|     |  0|     |  0|  0| 0.0|   | 13.0| 11.0|230|  8|   |15.00|  |
\n20150805 1100| 10|113| -RW |100|     |  0|     |  0|100| 0.1| RA| 13.0| 11.0|277| 11|   |10.00|  |
\n-------------+---+---+-----+---+-----+---+-----+---+---+----+---+-----+-----+---+---+---+-----+--+
\n20150805 1200| 10| 93| -RW |100|     |  0|     |  0|100| 0.1| RA| 13.0| 10.8|225|  9|   | 7.00|  |
\n-------------+---+---+-----+---+-----+---+-----+---+---+----+---+-----+-----+---+---+---+-----+--+
\n20150805 1300|  8|999| -RW |100|     |  0|     |  0| 33| 0.1| RA| 13.9| 11.4|163|  6|   |15.00|  |
\n20150805 1400|  8|999| -RW |100|     |  0|     |  0| 31| 0.1| RA| 14.4| 11.5|129|  7|   |15.00|  |
\n20150805 1500|  8|999| -RW |100|     |  0|     |  0| 26| 0.0|   | 14.9| 11.6|134| 12|   |15.00|  |
\n-------------+---+---+-----+---+-----+---+-----+---+---+----+---+-----+-----+---+---+---+-----+--+
\n20150805 1600|  9|999|     |  0|     |  0|     |  0| 12| 0.0|   | 15.5| 11.4|196|  6|   |15.00|  |
\n20150805 1700|  5|   |     |  0|     |  0|     |  0| 12| 0.0|   | 16.1| 11.0|289|  8|   |15.00|  |
\n20150805 1800| 10|999|     |  0|     |  0|     |  0| 10| 0.0|   | 16.7| 10.7|335| 15|   |15.00|  |
\n-------------+---+---+-----+---+-----+---+-----+---+---+----+---+-----+-----+---+---+---+-----+--+
\n20150805 1900| 10|999|     |  0|     |  0|     |  0| 13| 0.0|   | 16.7| 10.2|353| 17|   |15.00|  |
\n20150805 2000|  9|999|     |  0|     |  0|     |  0| 17| 0.0|   | 17.1| 10.1|349| 18|   |15.00|  |
\n20150805 2100| 10|999|     |  0|     |  0|     |  0| 18| 0.0|   | 17.5| 10.0|346| 20|   |15.00|  |
\n-------------+---+---+-----+---+-----+---+-----+---+---+----+---+-----+-----+---+---+---+-----+--+
\n20150805 2200|  8|999|     |  0|     |  0|     |  0| 21| 0.0|   | 17.2| 10.4|354| 19|   |15.00|  |
\n20150805 2300| 10|999| -RW | 80| -T  | 20|     |  0| 24| 0.3| RA| 16.9| 10.9|  3| 18|   |15.00|  |
\n20150806 0000| 10|999| -RW | 60| -T  | 40|     |  0| 24| 1.6| RA| 16.6| 11.4| 13| 18|   |15.00|  |
\n-------------+---+---+-----+---+-----+---+-----+---+---+----+---+-----+-----+---+---+---+-----+---+.

Before my substrings, this string is repeated for every stations (a few hundred stations) and I use the STN: CODE and +. delimeter to isolate my desired station(CYYC here). Is there a better way to do the substrings and to assign the values to my weather objects?

\$\endgroup\$
4
  • \$\begingroup\$ Are you on .Net 3.5 or above? The code looks quite old fashioned (IMO) so just wanted to check that you're not limited to .Net 2.0 before I answer \$\endgroup\$
    – RobH
    Commented Aug 6, 2015 at 14:27
  • \$\begingroup\$ @RobH According to C:\Windows\Microsoft.NET\Framework I have v4.0.30319 , I don't have admin rights and only visual studio express for web, so I don't think I have any other way of looking what version I am running (no visual studio command prompt either). \$\endgroup\$
    – loli
    Commented Aug 6, 2015 at 14:43
  • 1
    \$\begingroup\$ It's in the properties of the project (i.e. right click => properties => Application => Target Framework) It sounds like you just file new'd a console app so will be .Net 4 by the looks of it. I'll answer in a mo \$\endgroup\$
    – RobH
    Commented Aug 6, 2015 at 14:47
  • \$\begingroup\$ @RobH .NET Framework 4.5 \$\endgroup\$
    – loli
    Commented Aug 6, 2015 at 14:49

1 Answer 1

6
\$\begingroup\$

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<string> 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<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");
}

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!

\$\endgroup\$
3
  • 1
    \$\begingroup\$ I've done LINQ 2 years ago, but I didn't do enough to think about using it when the opportunity arises. That's exactly the kind of answer I expected though thanks! Is there any advantage to using var? \$\endgroup\$
    – loli
    Commented Aug 6, 2015 at 15:12
  • 1
    \$\begingroup\$ Nice write up. Your GetDataRows has likely typo: cyycReport.Split should probably be weatherReport.Split. \$\endgroup\$
    – Rick Davin
    Commented Aug 6, 2015 at 15:47
  • \$\begingroup\$ @RickDavin - thanks: loli has done the honours :) \$\endgroup\$
    – RobH
    Commented Aug 6, 2015 at 17:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.