我有一个清单(简化)
[Kind] [Name]
null E
null W
4 T
5 G
6 Q
null L
null V
7 K
2 Z
0 F
我需要{E,L} - >其Kind == null和下一个Kind == null的项目
假设有一个ID正在增加且按顺序。
这在Linq看起来有可能吗?
答案 0 :(得分:9)
喜欢这个吗?
void Main()
{
List<SomeClass> list = new List<SomeClass>() {
new SomeClass() { Kind = null, Name = "E" },
new SomeClass() { Kind = null, Name = "W" },
new SomeClass() { Kind = 4, Name = "T" },
new SomeClass() { Kind = 5, Name = "G" },
...
};
var query = list.Where ((s, i) =>
!s.Kind.HasValue &&
list.ElementAtOrDefault(i + 1) != null &&
!list.ElementAt(i + 1).Kind.HasValue);
}
public class SomeClass
{
public int? Kind { get; set; }
public string Name { get; set; }
}
编辑:窃取@Jeff Marcado的解决方案,实现类似于上述用法的扩展方法,但有点干净,而不是让你处理索引:
public static IEnumerable<TSource> WhereWithLookahead<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, bool> predicate) where TSource : class
{
using(var enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
{
//empty
yield break;
}
var current = enumerator.Current;
while (enumerator.MoveNext())
{
var next = enumerator.Current;
if(predicate(current, next))
{
yield return current;
}
current = next;
}
if (predicate(current, null))
{
yield return current;
}
}
}
// Use:
var query2 = list.WhereWithLookahead((current, next) =>
!current.Kind.HasValue &&
(next != null) &&
next.Kind.HasValue);
答案 1 :(得分:5)
对于功能方法,您可以像这样实现一个先行枚举器:
IEnumerable<Item> collection = ...;
var lookahead = collection.Zip(collection.Skip(1), Tuple.Create);
枚举器将迭代每个项目的元组,它是以下项目。这排除了集合中的最后一项。然后,这只是执行查询的问题。
var query = collection.Zip(collection.Skip(1), Tuple.Create)
.Where(tuple => tuple.Item1.Kind == null && tuple.Item2.Kind == null)
.Select(tuple => tuple.Item1);
不幸的是,效率非常低。你要两次计算集合的长度,而且非常昂贵。
为此编写自己的枚举器会更好,所以你只能在一遍中浏览集合:
public static IEnumerable<TResult> LookAhead<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TSource, TResult> selector)
{
if (source == null) throw new ArugmentNullException("source");
if (selector == null) throw new ArugmentNullException("selector");
using (var enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
{
//empty
yield break;
}
var current = enumerator.Current;
while (enumerator.MoveNext())
{
var next = enumerator.Current;
yield return selector(current, next);
current = next;
}
}
}
然后查询变为:
var query = collection.LookAhead(Tuple.Create)
.Where(tuple => tuple.Item1.Kind == null && tuple.Item2.Kind == null)
.Select(tuple => tuple.Item1);