关于c#:Linq检查集合中的任何项目是否与任何其他项目匹配的方式

Linq way of checking that no items in a collection match any other item

我取一个线段集合,修剪任何重叠的部分,我应该得到一个不作为输出重叠的集合。

为了测试我的输出,我希望迭代集合中的每个项,并确保它不与任何其他项重叠。

目前我有以下代码:

1
2
3
4
5
6
7
foreach (var assay in compiledAssays)
{
    if (compiledAssays.Where(a => a != assay).Any(a => a.Overlaps(assay)))
    {
        throw new ApplicationException("Something went wrong.");
    }
}

它可读,但对我来说"闻起来很难闻"。似乎它至少要在集合中迭代三次才能进行测试。

有没有更好的方法来表达这个测试?


合并WhereAny条款将是一个很好的第一个改进:

1
2
3
4
5
6
7
foreach (var assay in compiledAssays)
{
    if (compiledAssays.Any(a => a != assay && a.Overlaps(assay)))
    {
        throw new ApplicationException("Something went wrong.");
    }
}

你也可以试着更简洁些:

1
2
3
4
if (compiledAssays.Any(a => compiledAssays.Any(b => a != b && a.Overlaps(b))))
{
    throw new ApplicationException("Something went wrong."");
}

否则,如果您主要关心的是最小化执行的循环的数量,那么我不会使用LINQ。我会这样做(假设compiledAssays是一个数组,根据需要进行调整):

1
2
3
4
5
6
7
8
9
10
for (int i = 0; i < compiledAssays.Length; i++)
{
    for (int j = i + 1; j < compiledAssays.Length; j++)
    {
        if (compiledAssays[i].Overlaps(compiledAssays[j]))
        {
            throw new ApplicationException("Something went wrong.");
        }
    }
}

编辑:陈雷蒙的一个非常中肯的评论。

最后一个选项假设Overlaps函数是对称的。

换句话说,a.Overlaps(b)将始终返回与b.Overlaps(a)相同的值。如果不是这样,那么我最后的选择是错误的。


您的第一个Where子句排除了精确的重复项(取决于!=被定义为用于assay的内容),因此您可以使用compiledAssays.Distinct作为基枚举,但是如果您可以使用某种类型来优化对重叠的搜索,但是以额外的循环为代价,现在接受的答案的显式双精度除了目前不排除所有重复项之外,OP很好。应该是:

1
2
3
4
5
6
7
8
9
10
11
for (int i = 0; i < compiledAssays.Length; i++)
{
    for (int j = i + 1; j < compiledAssays.Length; j++)
    {
        if (compiledAssays[i] != compiledAssays[j]
          && compiledAssays[i].Overlaps(compiledAssays[j]))
        {
            throw new ApplicationException("Something went wrong.");
        }
    }
}

为了复制操作,再次假设Overlaps是对称的。