如何在没有第二个LINQ查询的情况下获得排除集合
本文关键字:情况下 集合 排除 查询 LINQ 第二个 | 更新日期: 2023-09-27 18:09:11
我有一个LINQ查询,看起来像这样:
var p = option.GetType().GetProperties().Where(t => t.PropertyType == typeof(bool));
获取查询中没有包含的项的最有效方法是什么,而不需要对列表执行第二次迭代。
我可以很容易地做到这一点与for
循环,但我想知道是否有一个简写与LINQ。
var p = option.GetType().GetProperties().ToLookup(t => t.PropertyType == typeof(bool));
var bools = p[true];
var notBools = p[false];
.ToLookup()
用于基于key函数对IEnumerable进行分区。在本例中,它将返回一个Lookup,其中最多包含2个项。Lookup中的项可以使用类似于dictionary的键来访问。
.ToLookup()
立即求值,是一个O(n)操作,在结果查找中访问分区是一个O(1)操作。
Lookup与Dictionary非常相似,并且具有相似的泛型参数(Key类型和Value类型)。但是,Dictionary将一个键映射到单个值,而Lookup将一个键映射到一组值。查找可以通过IDictionary<TKey, IEnumerable<TValue>>
.GroupBy()
也可以使用。但与.ToLookup()
不同的是,GroupBy是延迟求值的,可能会被多次枚举。.ToLookup()
立即求值,工作只做一次。
没有要求的东西是得不到的。所以,如果你排除了除bool
之外的所有元素,你就不能指望以后能得到它们。你需要问他们。
对于它的价值,如果你需要两者,一个你想要的和所有其他在一个查询,你可以GroupBy
这个条件或使用ToLookup
,我更喜欢:
var isboolOrNotLookup = option.GetType().GetProperties()
.ToLookup(t => t.PropertyType == typeof(bool)); // use PropertyType instead
现在可以使用此查找进行进一步处理。例如,如果你想要一个所有bool属性的集合:
List<System.Reflection.PropertyInfo> boolTypes = isboolOrNotLookup[true].ToList();
或者只是计数:
int boolCount = isboolOrNotLookup[true].Count();
所以如果你想处理所有非bool
:
foreach(System.Reflection.PropertyInfo prop in isboolOrNotLookup[false])
{
}
好吧,你可以选择source.Except(p)
,但它会重复列表并执行许多比较。
我想说-写一个扩展方法,使用foreach
,基本上把列表分成两个目的地。或者类似这样的。
如何:
public class UnzipResult<T>{
private readonly IEnumearator<T> _enumerator;
private readonly Func<T, bool> _filter;
private readonly Queue<T> _nonMatching = new Queue<T>();
private readonly Queue<T> _matching = new Queue<T>();
public IEnumerable<T> Matching {get{
if(_matching.Count > 0)
yield return _matching.Dequeue();
else {
while(_enumerator.MoveNext()){
if(_filter(_enumerator.Current))
yield return _enumerator.Current;
else
_nonMatching.Enqueue(_enumerator.Current);
}
yield break;
}
}}
public IEnumerable<T> Rest {get{
if(_matching.Count > 0)
yield return _nonMatching.Dequeue();
else {
while(_enumerator.MoveNext()){
if(!_filter(_enumerator.Current))
yield return _enumerator.Current;
else
_matching.Enqueue(_enumerator.Current);
}
yield break;
}
}}
public UnzipResult(IEnumerable<T> source, Func<T, bool> filter){
_enumerator = source.GetEnumerator();
_filter = filter;
}
}
public static UnzipResult<T> Unzip(this IEnumerable<T> source, Func<T,bool> filter){
return new UnzipResult(source, filter);
}
它是用记事本写的,所以可能无法编译,但我的想法是:无论你枚举的是什么集合(匹配的还是不匹配的),你只枚举一次源。它应该相当好地工作与那些讨厌的无限集合(想想yield return random.Next()
),除非所有的元素做/不满足filter
。