我有一个LINQ查询,如下所示:
var p = option.GetType().GetProperties().Where(t => t.PropertyType == typeof(bool));
获取未包含在此查询中的项目的最有效方法是什么,而不对列表执行第二次迭代。
我可以使用for
循环轻松完成此操作,但我想知道是否有LINQ的简写。
答案 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
。