Linq中嵌套选择的替代方法

时间:2013-08-18 17:16:17

标签: c# linq

在集群项目上工作时,我偶然发现了这个问题,我想弄清楚是否有一个比我想出的更好的解决方案。

问题:给定R ^ n中的List<Point> Points个点(您可以将每个点视为维数n的双数组),double minDistance和距离Func<Point,Point,double> dist,写一个LINQ表达式,根据dist,为每个点返回列表中比minDistance更接近他的其他点的集合。

我的解决方案如下:

        var lst = Points.Select( 
                x => Points.Where(z => dist(x, z) < minDistance)
                    .ToList() )
                .ToList();

所以,在注意到

之后
  • 使用LINQ可能不是最好的主意,因为你可以计算每个距离两次
  • 问题没有多少实际用途
  • 我的代码,即使看起来很糟糕,也适用

我有以下问题:

  1. 是否可以在查询表达式中翻译我的代码?如果是的话,怎么样?
  2. 有没有更好的方法以点符号解决这个问题?

3 个答案:

答案 0 :(得分:3)

问题定义,你想要“为每一点,一组其他点”使得没有内部查询就无法解决 - 你可以巧妙地伪装它。如果您可以更改数据存储策略,并且不遵守LINQ,那么通常会有很多Nearest Neighbour Search问题的方法。例如,您可以根据它们在一个轴上的值来保存点,这可以通过在没有完全距离计算的情况下消除早期的一些候选来加速对邻居的查询。以下是使用此方法的论文:Flexible Metric Nearest Neighbor Classification

答案 1 :(得分:0)

因为PointsList,您可以利用您可以通过索引访问每个项目的事实。因此,您可以避免将每个项目与以下内容进行两次比较:

var lst = 
    from i in Enumerable.Range(0, Points.Length)
    from j in Enumerable.Range(i + 1, Points.Length - i - 1)
    where dist(Points[i], Points[j]) < minDistance
    select new 
    {
        x = Points[i], y = Points[j]
    };

这将返回一个由彼此minDistance内的所有点组成的集合,但不完全是您想要的结果。如果你想将它变成某种Lookup,那么你可以看到哪些点接近给定点你可以这样做:

var lst = 
    (from i in Enumerable.Range(0, Points.Length)
     from j in Enumerable.Range(i + 1, Points.Length - i - 1)
     where dist(Points[i], Points[j]) < minDistance
     select new { x = Points[i], y = Points[j] })
    .SelectMany(pair => new[] { pair, { x = pair.y, y = pair.x })
    .ToLookup(pair => pair.x, pair => pair.y);

答案 2 :(得分:0)

我认为你可以在你的Property课程中添加一些bool Point来标记它已被浏览以防止两次调用dist,如下所示:

public class Point {
   //....
   public bool IsBrowsed {get;set;}
}
var lst = Points.Select( 
                 x => {
                       var list = Points.Where(z =>!z.IsBrowsed&&dist(x, z) < minDistance).ToList();
                       x.IsBrowsed = true;
                       return list;
                      })
                 .ToList();