按相同顺序对两个单独的列表进行排序?

时间:2012-01-20 15:12:14

标签: c# .net

首先要制定一些限制措施。由于我正在编写这个环境,我无法创建自己的类或方法。只是基本的程序代码。它在CMS中,我的代码在方法本身内执行。

这是我的问题

在此页面上,我进行数据库查询,加载所有700个商店位置。然后,我根据查询字符串中的lat和lng值与数据库中的lat和lng值进行距离计算,以查找50公里范围内的商店。每一个都在该距离内,我目前添加到List<DataRow>。我还获取距离结果,将其四舍五入到一个小数位,并将其存储到Double类型的简单列表中。我想要做的,基本上是排序这些,所以当我输出商店+距离值时,它排序最短到最长距离。我在考虑将List<DataRow>List<Double>组合切换为Dictionary<Double, DataRow>并在那里使用排序,但当然有些情况下两个地方具有相同的距离值,因此它会不是唯一的。我可以使用另一种类型的集合类型,或者你能推荐一种好的方法对数据进行排序吗?

以下是我需要视觉的代码:

PRA对象基本上是我们用于处理CMS后端方面的主要对象。在这种情况下,我使用简写方法查询数据,并检查请求数据中的几个变量。其余的都是内置的.net东西。

List<DataRow> locationsInRange = new List<DataRow>();
List<Double> distances = new List<Double>();
if(!String.IsNullOrEmpty(PRA.Request.QueryString["lat"]) && !String.IsNullOrEmpty(PRA.Request.QueryString["lng"])) {
  Double earthRadius = 6371.0;
  Double maxDistance = 50.0;

  var locations = PRA.QueryDataRows("*", "", "{Location}", "showweb");
  Double lat =  Double.Parse(PRA.Request.QueryString["lat"]);
  Double lng =  Double.Parse(PRA.Request.QueryString["lng"]);

  if(!String.IsNullOrEmpty(PRA.Request.QueryString["radius"])) {
    Double temp = Double.Parse(PRA.Request.QueryString["radius"]);
    if(temp > 0) {
      maxDistance = temp;
    }
  }

  bool firstError = true;
  foreach(var l in locations) {
    Double latSecond = 0.0;
    Double lngSecond = 0.0;
    try {
      latSecond = Double.Parse(l["lat"].ToString());
      lngSecond = Double.Parse(l["lng"].ToString());
    }
    catch(Exception ex) {
      // do nothing. The lat and lng may not of been valid or not returned a result
    }


    Double dLat = Math.PI * ((lat - latSecond) / 180.0);
    Double dLon = Math.PI * ((lng - lngSecond) / 180.0);

    Double lat1 = Math.PI * (latSecond / 180.0);
    Double lat2 = Math.PI * (lat / 180.0);

    Double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Sin(dLon / 2) * Math.Sin(dLon / 2) * Math.Cos(lat1) * Math.Cos(lat2);
    Double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
    if(earthRadius * c <= (Double) maxDistance) {
      locationsInRange.Add(l);
      distances.Add(Math.Round(earthRadius * c, 1));
    }
  }

}

4 个答案:

答案 0 :(得分:2)

使用由Tuple类型...

表示的对列表(数据,距离)
var locations = new List<Tuple<DataRow, double>>();
locations.Add(Tuple.Create(row, distance));
locations.Sort((x, y) => x.Item2.CompareTo(y.Item2));

答案 1 :(得分:1)

您可以在方法中间使用var关键字来让编译器生成匿名类。

var combinedInstance = new {Row = new DataRow(), Distance = 0.0m};

您可以在方法的中间使用lambda表示法来让编译器生成新方法。

Func<Location, Location, decimal> getDistance = (loc1, loc2) =>
{
  return 0.0m; //TODO implement
} 

var combinedList = locationsInRange
  .Select((row, i) => new {Row = row, Distance = distances[i]})
  .OrderBy(x => x.Distance)
  .ToList();
// now replace the original lists with newly ordered lists.
locationsInRange = combinedList.Select(x => x.Row).ToList();
distances = combinedList.Select(x => x.Distance).ToList();

答案 2 :(得分:0)

干净的方法是创建一个ICompareable类,其中包含DataRowDouble,其比较默认为Double的比较。然后,您可以使用SortedList进行自然表示。

由于这种干净的方式根据应用程序的设计(我的第一次覆盖)是不可能的,我们需要一种肮脏的方式,我的建议是

  • 假设您的商店列表中有一些独特的价值(位置似乎是一个)
  • 创建排序String.Format("{0:0000000000}/{1}",Math.Round(distance*10000),unique_criterium)
  • 的字符串表示形式
  • 将其存储在SortedList
  • 迭代SortedList时,解析String back

答案 3 :(得分:0)

如果不能将重构转换为单个数据类型,则可以对索引进行排序并使用查找表。这足以与一些遗留代码库接口。

独立示例:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Some disjoint datasets
        List<int> scores = new List<int>{3,5,2,8,4};
        List<string> names = new List<string>{"three","five","two","eight","four"};

        // Sequence of indices
        List<int> indices = new List<int>(System.Linq.Enumerable.Range(0, scores.Count));

        // Sort indices, based on corresponding score
        indices.Sort(delegate(int a, int b) { return scores[a] - scores[b]; });

        for(int i = 0; i < indices.Count; ++i) 
        {
            // Use lookup table for indices
            int index = indices[i];
            Console.WriteLine(string.Format("Name: {0}, score: {1}", names[index], scores[index]));
        }
    }
}