希望是一个快速的问题。我有一个类型为Position的 IEnumerable ,其中Position的定义如下:
public class Position {
public double Latitude { get; set; }
public double Longitude { get; set; }
}
我需要做的是快速排序 IEnumerable ,找到与彼此一定距离内的元素。 IEnumerable中的元素不会以任何特定的顺序填充,但在任何时候我都需要能够计算IEnumerable的哪些成员落在彼此的 x km之内。
现在,我已经有了一个Haversine实现,为了论证,我们可以说它叫做GetDistance并且有以下签名:
double GetDistance(Position one, Position two);
我有一些想法,但没有一个想法特别有效。为了提供更多信息,IEnumerable不太可能在任何时候持有超过10,000件物品。
我想要达到的是一些东西,也许是一种扩展方法,它允许我调用它来返回一个IEnumerable,它只包含符合条件的原始集合中的子集,例如:
OriginalEnumerable.GetMembersCloserThan(kilometers: 100);
任何帮助,非常感谢。
编辑:为清楚起见,请考虑我要搜索的IEnumerable描述半径为 r 的圆。它的成员是圆圈内的坐标。我正在尝试确定哪些成员(点)在彼此的给定距离内。
答案 0 :(得分:3)
这样的东西?假设GetDistance
可用。
public static IEnumerable<Position> GetMembersCloserThan(this IEnumerable<Position> positions, double maxDistance)
{
return positions.Where(a => positions.Any(b => a != b && GetDistance(a, b) < maxDistance));
}
编辑我现在看到您对性能也很感兴趣。上面的速度并不是特别快,但由于数学比较距离非常简单,所以速度也不是很慢。如果它符合您的要求,请告诉我。
编辑2 这个更快 - 它不会针对过去的失败进行测试,并会自动为成功列表添加匹配
public static IEnumerable<Position> GetMembersCloserThan(this IEnumerable<Position> positions, double maxDistance)
{
List<Position> closePositions = new List<Position>();
List<Position> testablePositions = positions.ToList();
foreach (Position position in positions)
{
// Skip this one, it has already been matched.
if (closePositions.Contains(position))
continue;
bool isClose = false;
foreach (Position testAgainstPosition in testablePositions)
{
if (position == testAgainstPosition)
continue;
if (GetDistance(position, testAgainstPosition) < maxDistance)
{
// Both the position and the tested position pass.
closePositions.Add(position);
closePositions.Add(testAgainstPosition);
isClose = true;
break;
}
}
// Don't test against this position in the future, it was already checked.
if (!isClose)
{
testablePositions.Remove(position);
}
}
return closePositions;
}
答案 1 :(得分:1)
如果您需要更高的性能:将项目放入按纬度排序的列表中。
要计算所需的位置集,请迭代其中一个位置。但是对于距离计算,您只需要考虑纬度不同的最大100km的项目。这意味着,您可以逐项返回,直到差异大于100km。但是,您需要环绕列表的末尾。 标记距离小于100km的所有项目(或yyield返回)并继续前进。
虽然我无法量化费用,但排序应按大型集合摊销。此外,如果大多数点位于相似的纬度,它可能会表现不佳。如果这是一个问题,请使用带圆角坐标的2D字典作为键。