如何根据LINQ查询中的选定结果过滤结果?

时间:2011-05-02 07:46:10

标签: c# .net linq

我有一个Foos列表,我想根据foo.HasBar进行过滤 Foo也有Baz属性 选择Foo时,应过滤所有具有相同Baz对象的Foos 是否可以使用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 = 1;,则不会执行其他Foo.HasBar = false; Foo.Baz = 2;上的其他迭代,也不会执行Foo.HasBar = true; 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);
}

5 个答案:

答案 0 :(得分:3)

使用IEnumerable<Foo>.Distinct,并以高效的方式实现您的equals运算符,其中Baz属性被选中,如果HasBar不是Baz,则忽略&&属性等于。您可以使用HasBar执行此操作,因为如果左侧表达式为false,则不会评估右侧表达式。

然后,根据IEnumerable<Foo>.WhereFoo进行过滤。

如果您不想使用Equals运算符弄乱Equals对象,或者您需要针对不同情况使用不同的IEqualityComparer<Foo>实现,请实现单独的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; } } 属性。如果你跳过了类本身的检查,它可能会导致细微的错误,因为人们可能期望它们是平等的。但是如果有一个名字很好的自定义比较器,人们就不太可能认为它会确保绝对平等。

以下是一些示例代码:

{{1}}

答案 1 :(得分:1)

var results = from f in Foos where (foo.HasBar) && (foo.Baz equals SelectedBaz) select f;

答案 2 :(得分:1)

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;

我能想到的最好的(现在)。

let的使用应该避免多次调用FirstOrDefault,因此假设FirstOrDefault的实现在找到结果后不会迭代,那么性能密集的HasBar将不会被调用多次。如果没有使用let,则应在where子句中使用FirstOrDefault。

答案 3 :(得分:0)

从您的代码中,您只需:

foos.Where(f => !foos.Where(f2 => f2.HasBar).Any(s => s.Baz == f.Baz));

答案 4 :(得分:0)

你可以简单地使用

var filtered = from f in foos 
               where foo.HasBar == true
               select f;