C# 如何根据LINQ查询中选定的结果筛选结果?

C# 如何根据LINQ查询中选定的结果筛选结果?,c#,.net,linq,C#,.net,Linq,我有一个要根据foo.HasBar筛选的foo列表 Foo还有一个物业Baz。 当选择一个Foo时,应过滤具有相同Baz对象的所有Foo。 是否可以使用LINQ查询来实现这一点,还是应该改用foreach 编辑:以下是一个示例数据集: Foo.HasBar = true; Foo.Baz = 1; Foo.HasBar = true; Foo.Baz = 1; Foo.HasBar = false; Foo.Baz = 1; Foo.HasBar = true; Foo.Baz = 2; Foo

我有一个要根据
foo.HasBar
筛选的foo列表
Foo还有一个物业Baz。
当选择一个Foo时,应过滤具有相同Baz对象的所有Foo。
是否可以使用LINQ查询来实现这一点,还是应该改用foreach

编辑:以下是一个示例数据集:

Foo.HasBar = true; Foo.Baz = 1;
Foo.HasBar = true; Foo.Baz = 1;
Foo.HasBar = false; Foo.Baz = 1;
Foo.HasBar = true; Foo.Baz = 2;
Foo.HasBar = false; Foo.Baz = 2;
我试图实现的是,在另一个
Foo.HasBar=true上没有其他迭代;Foo.Baz=1Foo.HasBar=false上执行code>或不再执行另一次迭代;Foo.Baz=2Foo.HasBar=true,将执行code>;Foo.Baz=2已被选中

下面是我如何使用foreach循环完成的:

var selectedFoos = new List<Foo>();

foreach(var foo in foos)
{
  if (selectedFoos.Exists(f => f.Baz == foo.Baz))
    continue;

  if (foo.HasBar)
     selectedFoos.Add(foo);
}
var selectedFoos=newlist();
foreach(foos中的var foo)
{
if(selectedFoos.Exists(f=>f.Baz==foo.Baz))
继续;
如果(foo.HasBar)
选择foos.Add(foo);
}

根据您的代码,您只需:

foos.Where(f => !foos.Where(f2 => f2.HasBar).Any(s => s.Baz == f.Baz));
你可以简单地跟着我走

var filtered = from f in foos 
               where foo.HasBar == true
               select f;
(目前)我能想出的最好办法

使用let应该避免多次调用FirstOrDefault,这样性能密集型HasBar的调用次数不会超过需要的次数,前提是FirstOrDefault的实现在找到结果后不会迭代。如果未首先使用let,则应在where子句中使用默认值。

使用
IEnumerable.Distinct
,并以性能方式实现equals运算符,其中选中
Baz
属性,如果
Baz
不相等,则忽略
HasBar
属性。可以使用
&&
执行此操作,因为如果左侧表达式为false,则不会计算右侧表达式

然后,使用
IEnumerable.Where
基于
HasBar
进行过滤

如果您不想使用
Equals
运算符使
Foo
对象杂乱无章,或者您需要针对不同情况使用不同的
Equals
实现,那么请实现一个单独的
IEqualityComparer

这还有一个优点,即在获取不同的值时,可以避免完全检查
HasBar
属性。如果您跳过了类本身的检查,可能会导致一些微妙的错误,因为人们可能期望它们是平等的。但是有了一个名字很好的自定义比较器,人们不太可能认为它将确保绝对平等

下面是一些示例代码:

IEnumerable<Foo> selectedFoos =
    sampleDataSet
        .Distinct(new PerformantFooComparer())
        .Where(f => f.HasBar);

// ...

private class PerformantFooComparer : IEqualityComparer<Foo>
{
    public bool Equals(Foo x, Foo y)
    {
        bool isXNull = x == null;
        bool isYNull = y == null;

        return isXNull == isYNull
            && isXNull
            || (
                x.Baz == y.Baz
                // && x.HasBar == y.HasBar
                // HasBar commented out to avoid performance overhead.
                // It is handled by a Where(foo => foo.HasBar) filter
                );
    }

    public int GetHashCode(Foo obj)
    {
        if (obj == null)
            return 0;

        // See: http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
        int hash = 17;
        hash = hash * 23 + obj.Baz.GetHashCode();
        // HasBar intentionally not hashed
        return hash;
    }
}
IEnumerable selectedFoos=
样本数据集
.Distinct(新的PerformanceFooComparer())
其中(f=>f.HasBar);
// ...
私有类PerformanceFooComparer:IEqualityComparer
{
公共布尔等于(Foo x,Foo y)
{
bool isXNull=x==null;
bool-isYNull=y==null;
返回isXNull==isYNull
&&isXNull
|| (
x、 Baz==y.Baz
//&&x.HasBar==y.HasBar
//HasBar注释掉了,以避免性能开销。
//它由Where(foo=>foo.HasBar)过滤器处理
);
}
公共int GetHashCode(Foo obj)
{
if(obj==null)
返回0;
//见:http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
int hash=17;
hash=hash*23+obj.Baz.GetHashCode();
//HasBar故意不散列
返回散列;
}
}

要删除另一个Foo中存在Baz的Foo,还是要选择不同的Baz?您只需要Foo.HasBar真值RT?@anishMarokey:是的,但HasBar是性能密集型的,所以我正在尝试优化。这就是为什么distinct不适合我的情况,但HasBar是一个真正的性能消费者。我正在尝试在这里进行优化。@if(selectedFoos.Exists(f=>f.Baz==foo.Baz))的作用是什么?如果没有,它也会过滤RT?如果查询已经选择了带有baz的foo,则无需选择具有相同baz的其他foo。因此它应该跳过它。但是在创建结果时我还没有选择Foos。很好。顺便说一句,如果你只对Baz进行哈希运算,就不需要素数运算。如果你使用这种解决方案,请确保对
performantfoocomarer
类进行三次斜杠注释,让人们知道它忽略了
HasBar
属性。@Stilgar:是的,绝对正确。在这种情况下,只需返回
obj.Baz.GetHashCode()
。不过,我假设他正在大力修改他的数据类型,所以我想确保他能够将示例扩展到多个属性。格雷厄姆:你的假设是正确的,我学到的知识比我想要的要多。我感谢你:)
var q = from f in foos
        group f by f.Baz into g
        let tempFoo = g.FirstOrDefault(foo => foo.HasBar)
        where tempFoo != null
        select tempFoo;
IEnumerable<Foo> selectedFoos =
    sampleDataSet
        .Distinct(new PerformantFooComparer())
        .Where(f => f.HasBar);

// ...

private class PerformantFooComparer : IEqualityComparer<Foo>
{
    public bool Equals(Foo x, Foo y)
    {
        bool isXNull = x == null;
        bool isYNull = y == null;

        return isXNull == isYNull
            && isXNull
            || (
                x.Baz == y.Baz
                // && x.HasBar == y.HasBar
                // HasBar commented out to avoid performance overhead.
                // It is handled by a Where(foo => foo.HasBar) filter
                );
    }

    public int GetHashCode(Foo obj)
    {
        if (obj == null)
            return 0;

        // See: http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
        int hash = 17;
        hash = hash * 23 + obj.Baz.GetHashCode();
        // HasBar intentionally not hashed
        return hash;
    }
}