如何在没有第二个LINQ查询的情况下获得排除集合

本文关键字:情况下 集合 排除 查询 LINQ 第二个 | 更新日期: 2023-09-27 18:09:11

我有一个LINQ查询,看起来像这样:

 var p = option.GetType().GetProperties().Where(t => t.PropertyType == typeof(bool));

获取查询中没有包含的项的最有效方法是什么,而不需要对列表执行第二次迭代。

我可以很容易地做到这一点与for循环,但我想知道是否有一个简写与LINQ。

如何在没有第二个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