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

时间:2015-08-21 13:26:59

标签: c#

我有一个LINQ查询,如下所示:

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

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

我可以使用for循环轻松完成此操作,但我想知道是否有LINQ的简写。

3 个答案:

答案 0 :(得分:10)

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

var bools = p[true];

var notBools = p[false];

.ToLookup()用于根据键功能对IEnumerable进行分区。在这种情况下,它将返回一个Lookup,其中最多包含2个项目。可以使用类似于IDictionary的键访问Lookup中的项目。

立即评估

.ToLookup()并进行O(n)操作,并在生成的Lookup中访问分区是O(1)操作。

Lookup与Dictionary非常相似,并且具有类似的通用参数(Key类型和Value类型)。但是,在Dictionary将键映射到单个值的情况下,Lookup会将键映射到一组值。查找可以实现为IDictionary<TKey, IEnumerable<TValue>>

.GroupBy()也可以使用。但它与.ToLookup()的不同之处在于GroupBy是惰性求值的,并且可能被多次枚举。 .ToLookup()会立即进行评估,工作只进行一次。

答案 1 :(得分:2)

你不能得到你不需要的东西。因此,如果除了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])
{

}

答案 2 :(得分:-2)

好吧,你可以选择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())相当好,除非所有元素都执行{not} filter