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=1将在Foo.HasBar=false上执行code>或不再执行另一次迭代;Foo.Baz=2如果Foo.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;
}
}