C# 查找与双精度数组最近的匹配项

C# 查找与双精度数组最近的匹配项,c#,asp.net,C#,Asp.net,给定下面的代码,如何将对象的值列表与测试值进行比较 我正在构建一个地理定位应用程序。我将输入经度和纬度,并希望服务返回最接近这些值的位置 我开始转换为字符串,并将值的格式设置为小数点后两位,但这似乎有点太狭隘了,我正在寻找一个更优雅的解决方案 public class Location : IEnumerable { public string label { get; set; } public double lat { get; set; } public doubl

给定下面的代码,如何将对象的值列表与测试值进行比较

我正在构建一个地理定位应用程序。我将输入经度和纬度,并希望服务返回最接近这些值的位置

我开始转换为字符串,并将值的格式设置为小数点后两位,但这似乎有点太狭隘了,我正在寻找一个更优雅的解决方案

public class Location : IEnumerable
{
    public string label { get; set; }
    public double lat { get; set; }
    public double lon { get; set; }

    //Implement IEnumerable
    public IEnumerator GetEnumerator()
    {
        return (IEnumerator)this;
    }

}
[HandleError]
public class HomeController : Controller
{
    private List<Location> myList = new List<Location>
 {             
    new Location {
        label="Atlanta Midtown", 
        lon=33.657674, 
        lat=-84.423130},
    new Location {
        label="Atlanta Airport", 
        lon=33.794151, 
        lat=-84.387228},
    new Location {
        label="Stamford, CT", 
        lon=41.053758, 
        lat=-73.530979}, ...
}

 public static int Main(String[] args)
 {
     string inLat = "-80.987654";
     double dblInLat = double.Parse(inLat);

     // here's where I would like to find the closest location to the inLat
     // once I figure out this, I'll implement the Longitude, and I'll be set
 }
公共类位置:IEnumerable
{
公共字符串标签{get;set;}
公共双lat{get;set;}
公共双lon{get;set;}
//实现IEnumerable
公共IEnumerator GetEnumerator()
{
返回(IEnumerator)这个;
}
}
[手机错误]
公共类HomeController:控制器
{
私有列表myList=新列表
{             
新位置{
label=“亚特兰大市中心”,
lon=33.657674,
lat=-84.423130},
新位置{
label=“亚特兰大机场”,
lon=33.794151,
lat=-84.387228},
新位置{
label=“康涅狄格州斯坦福德市”,
lon=41.053758,
lat=-73.530979}。。。
}
公共静态int Main(字符串[]args)
{
字符串嵌入=“-80.987654”;
double dblInLat=double.Parse(inslat);
//我想在这里找到离镶嵌最近的位置
//一旦我弄明白了这一点,我将实现经度,我将被设置
}

我认为最简单的方法是执行以下操作。但不是最有效的:)

遍历列表并计算每个位置与参考位置之间的距离。在每个步骤中,检查这是否是迄今为止看到的最短距离,并将其存储。一旦获得列表末尾的最短距离,您将在存储的变量中拥有最近的位置

如果你谈论的是大量的位置,你计划做很多这种性质的空间查询,你可以考虑在数据上建立四叉树索引。 这是我在快速“Bing”后发现的一个链接,我希望它有助于距离计算。请参考此链接:


你需要多精确?它被称为大圆距离


例如,请参见

如果您不想最终得到奇怪的结果,您需要使用正确的距离公式:

double CalculateDistance(double lat1, double lon1, double lat2, double lon2)
{
    const double R = 6371;
    return Math.Acos(
        Math.Sin(lat1) * Math.Sin(lat2) +
        Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(lon2 - lon1)) * R;
}
我希望这是正确的公式,我的数学可能有点生疏。所有参数都需要以rads为单位,因此,如果您以度为单位输入,请编写一个实用方法:

double DegToRad(double deg)
{
    return deg * Math.PI / 180.0;
}
无论如何,在此之后,您可以计算出最短距离,如下所示:

Location GetClosestLocation(Location origin)
{
    double olatr = DegToRad(origin.Lat);
    double olonr = DegToRad(origin.Lon);
    return
        (from l in locations
         let latr = DegToRad(l.Lat)
         let lonr = DegToRad(l.Lon)
         orderby CalculateDistance(latr, lonr, olatr, olonr))
        .FirstOrDefault();
}
从技术上讲,这并不是性能最好的解决方案,因为它必须进行排序,但是没有好看的Linq扩展方法来使用投影进行min。如果您需要,您必须编写自己的
foreach
循环:

Location GetClosestLocation(Location origin)
{
    double olatr = DegToRad(origin.Lat);
    double olonr = DegToRad(origin.Lon);
    Location closest = null;
    double minDistance = double.MaxValue;
    foreach (Location l in locations)
    {
        double latr = DegToRad(l.Lat);
        double lonr = DegToRad(l.Lon);
        double dist = CalculateDistance(latr, lonr, olatr, olonr));
        if (dist < minDistance)
        {
            minDistance = dist;
            closest = l;
        }
    }
    return closest;
}
Location GetClosesLocation(位置原点)
{
双olatr=DegToRad(origin.Lat);
双Olor=DegToRad(origin.Lon);
位置最近=空;
double minDistance=double.MaxValue;
foreach(位置中的位置l)
{
双拉特=DegToRad(l拉特);
双lonr=DegToRad(l.Lon);
双距离=计算距离(latr、lonr、olatr、OLOR);
如果(距离<距离)
{
距离=距离;
最近的=l;
}
}
返回最近的位置;
}
我发现有人用几种不同的方法中的一种来计算全球两个距离之间的距离。我不得不将.NET项目转换为更新的VS2008,但这似乎很好。然后我将此项目添加到我的解决方案中并引用了它

我的代码变成:

string inLat = "-80.987654";
string inLon = "33.521478";
var miles = GetNearestLocation(inLat, inLon);

public double GetNearestLocation(string lat, string lon)
{
    double dblInLat = double.Parse(lat);
    double dblInLon = double.Parse(lon);

    // instantiate the calculator
    GeodeticCalculator geoCalc = new GeodeticCalculator();

    // select a reference elllipsoid
    Ellipsoid reference = Ellipsoid.WGS84;

    // set user's current coordinates
    GlobalCoordinates userLocation;
    userLocation = new GlobalCoordinates(
        new Angle(dblInLon), new Angle(dblInLat)
    );

    // set example coordinates- when fully fleshed out, 
    //    this would be passed into this method
    GlobalCoordinates testLocation;
    testLocation= new GlobalCoordinates(
        new Angle(41.88253), new Angle(-87.624207) // lon, then lat
    );

    // calculate the geodetic curve
    GeodeticCurve geoCurve = geoCalc.CalculateGeodeticCurve(reference, userLocation, testLocation);
    double ellipseKilometers = geoCurve.EllipsoidalDistance / 1000.0;
    double ellipseMiles = ellipseKilometers * 0.621371192;
    /*
    Console.WriteLine("2-D path from input location to test location using WGS84");
    Console.WriteLine("   Ellipsoidal Distance: {0:0.00} kilometers ({1:0.00} miles)", ellipseKilometers, ellipseMiles);
    Console.WriteLine("   Azimuth:              {0:0.00} degrees", geoCurve.Azimuth.Degrees);
    Console.WriteLine("   Reverse Azimuth:      {0:0.00} degrees", geoCurve.ReverseAzimuth.Degrees);
    */
    return ellipseMiles;
}

您的意思是将dblInLat值与myList值进行比较并找到最接近的匹配项吗?我的意思是循环浏览位置列表并查看每个“lat”并将其与我的dblInLat进行比较。我正在查找最接近的值-大于或小于。换句话说,我会将传入变量与列表中的每个lat进行比较,并查找它们之间的最小差异。这听起来像是我应该做的。但我实际做的是使用我在此处找到的.NET解决方案: