4

My brain is not working and I am trying to make something harder than I think it really should be and I need another set of eyes. I have the following in a text file

|TS|170702/2300|170703/0503|42.80 -102.64 39.76 -102.64 39.44 -99.37 42.48 -99.37
|TS|170703/0505|170703/0905|40.22 -97.30 38.63 -97.30 38.19 -101.03 39.78 -101.03

what the above means...(|watchtype|watchstart|watchend| lat/long pairs)

The problem I'm having is that I need to take EACH ROW (could be 0 or could be 100+) and create a polygon on a map to mark the location of these storm watches. I currently have the following.

MODEL

public class WatchPolygons
{
    public string WatchType { get; set; }
    public string WatchStart { get; set; }
    public string WatchEnd { get; set; }
    public List<lat_longPairs> Lat_Long_Pairs {get; set;}
}

public class lat_longPairs
{
    public decimal latitude { get; set; }
    public decimal longitude { get; set; }
}

CONTROLLER

public JsonResult GetWatchPath()
{
    var watchFilePaths = ConfigurationManager.AppSettings["watchFilePath"];
    return Json(Directory.GetFiles(Server.MapPath(watchFilePaths), "current*.txt"), JsonRequestBehavior.AllowGet);
}

[HttpGet]
public ActionResult GetWatchData(string watchPath)
{
    var stringData = new List<string>();
    using (var reader = new StreamReader(watchPath))
    {
        while (!reader.EndOfStream)
        {
            var data = reader.ReadLine().Trim();

            if (!string.IsNullOrEmpty(data))
                stringData.Add(data);
        }

    }

    return Json((from item in stringData
                 select item.Split(new char [] { '|' }, StringSplitOptions.RemoveEmptyEntries)
                into rawData
                 select new WatchPolygons
                 {
                     WatchType = rawData[0],
                     WatchStart = rawData[1],
                     WatchEnd = rawData[2]
                 }).ToList(), JsonRequestBehavior.AllowGet);
}

I know I am missing the latlong pairs = rawData. I don't have it in the code because in the model it's a list and I can't easily convert the list to string the way I need it.

What am I missing? I believe I need to read over each line then read over each group to get the lat/long pairs. Just not sure.

2 Answers 2

4

You just need to parse rawData[3], containing the string with space separated lat/lon pairs. This is a naive implementation that will break when the input string does not contain pairs of numbers or when the current locale doesn't use a dot as a decimal separator:

private static List<lat_longPairs> ParseLatLon(string input)
{
    var numbers = input.Split(new [] { " " }, StringSplitOptions.RemoveEmptyEntries)
                       .Select(i => decimal.Parse(i))
                       .ToArray();

    var latLonPairs = new List<lat_longPairs>();

    for (int i = 0; i < numbers.Length; i += 2)
    {
        latLonPairs.Add(new lat_longPairs
        {
            latitude = numbers[i],
            longitude = numbers[i + 1],
        });
    }

    return latLonPairs;
}

Then call it from where you're projecting the polygons:

select new WatchPolygons
{
    WatchType = rawData[0],
    WatchStart = rawData[1],
    WatchEnd = rawData[2],
    Lat_Long_Pairs = ParseLatLon(rawData[3])
}

You may want to move the parsing code away from the controller as well, into its own class.

Sign up to request clarification or add additional context in comments.

2 Comments

There's no reason not to use decimal.Parse(i, NumberFormatInfo.InvariantInfo) to ensure consistent parsing in all cultures.
@dbc the dot as culture-sensitive decimal separator is only one of a couple potential problems with parsing this string, as explained in this answer. It requires more error handling than just that; I wanted to show the pattern to solve this problem, not a complete, fully tested and robust solution, that's up to the reader.
0

You can use GroupBy since two set make a coordinate.

        var str = "|TS|170702/2300|170703/0503|42.80 -102.64 39.76 -102.64 39.44 -99.37 42.48 -99.37";  
        int itemsInGroup = 2;
        var pairs = str.Split('|')[4].Split(' ').
                    // Give each set of coordinate a group number.
                    Select((n, i) => new { GroupNumber = i / itemsInGroup, Number = n }).
                    GroupBy(n => n.GroupNumber).
                    Select(g => 
                    {
                        var coordinate = g.Select(n => n.Number).ToList();
                        return new lat_longPairs
                        {
                            latitude = decimal.Parse(coordinate[0], NumberFormatInfo.InvariantInfo),
                            longitude = decimal.Parse(coordinate[1], NumberFormatInfo.InvariantInfo),
                        };
        });

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.