按相同顺序对两个单独的列表进行排序
本文关键字:单独 两个 列表 排序 顺序 | 更新日期: 2023-09-27 18:20:58
只是先制定一些限制。由于我编写代码的环境,我无法创建自己的类或方法。只是基本的程序代码。它在CMS中,我的代码在方法本身中执行。
这是我的问题
在这个页面上,我做了一个数据库查询,加载了所有700多个商店的位置。然后,我根据查询字符串中的lat和lng值与数据库中的值进行距离计算,以查找50公里内的商店。在这个距离内的每一个,我当前都添加到List<DataRow>
中。我还获取距离结果,将其四舍五入到小数点后一位,并将其存储到Double类型的简单列表中。我想做的,基本上是对这些进行排序,所以当我输出stores+距离值时,它是从最短到最长的距离排序。我想把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));
}
}
}
使用由Tuple
类型表示的对(数据、距离)列表。。。
var locations = new List<Tuple<DataRow, double>>();
locations.Add(Tuple.Create(row, distance));
locations.Sort((x, y) => x.Item2.CompareTo(y.Item2));
您可以在方法中间使用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();
如果不能重构为单个数据类型,则可以对索引进行排序并使用查找表。这对于与一些遗留代码库接口来说已经足够好了。
独立示例:
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]));
}
}
}
干净的方法是创建一个包含DataRow
和Double
的ICompareable
类,比较默认为Double
的比较。然后可以使用SortedList
作为自然表示。
由于根据应用程序的设计(我第一次否决),这种干净的方式是不可能的,我们需要一种肮脏的方式,我的建议是
- 假设你的购物清单中有一些独特的价值(地点似乎就是其中之一)
- 创建排序为
String.Format("{0:0000000000}/{1}",Math.Round(distance*10000),unique_criterium)
的字符串表示 - 将其存储在SortedList中
- 迭代SortedList时,将String解析回