2011-03-05 87 views
3

还有就是要算它符合一些条件的元素数量的标准方式:LINQ查询问题

collection.Where(d=> d==something).Count(); 

我需要以下功能(伪COD):

collection.Where(d=> (d==something) && (d.Next == somethingElse)).Count(); 

编辑:d.Next - 是集合中d之后的下一个元素。

这是如何实现的?

+1

是'd.Next' D'或'的属性序列中的下一个元素? – Ani 2011-03-05 14:56:10

+0

不,下一个是集合中的下一个元素。 – Peter17 2011-03-05 15:00:54

回答

5

假设你所拥有的是一个涉及源序列中连续元素的谓词,你可以这样做:

int numMatches = collection.Zip(collection.Skip(1), (prev, next) => 
           prev == something && next == somethingElse) 
          .Count(match => match) 

在应用过滤器之前,这会在序列的一个延迟版本上叠加序列。

+1

那简单而优雅。谢谢! – Peter17 2011-03-05 15:05:53

+1

我真的很喜欢这个解决方案,但我认为它枚举IEnumerable两次由于zip/skip的组合。这可能导致“IEnumerable”的某些实现出现问题。尽管如此,使用类列表实现仍然很安全。 – Femaref 2011-03-05 16:39:05

3
var result = collection.Count(d => 
    d == something && 
    d.Next == somethingElse 
); 

编辑:的情况下,如果d.Nextd属性或序列中的下一个元素:

var result = collection.Zip(
    collection.Skip(1), 
    (first, second) => first == something && second == somethingElse 
).Count(i => i); 
+1

我想问题是'd'没有'Next'属性。 – Femaref 2011-03-05 14:56:50

+0

我的意思是,下一个是集合中的下一个元素。 – Peter17 2011-03-05 15:01:23

+0

@Femaref,@ Peter17:更新了我的回答 – Alex 2011-03-05 15:05:21

1

可以写一个新的操作符(假定LINQ到对象)明确地使用枚举器来检查它。

代码:

public static partial class Enumerable 
{ 
    public static IEnumerable<TSource> WhereNext<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate, TSource next) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 
     if (predicate == null) 
      throw new ArgumentNullException("predicate"); 

     return WhereNextImpl(source, predicate, next); 
    } 

    private static IEnumerable<TSource> WhereNextImpl<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate, TSource next) 
    { 
     using (var enumerator = source.GetEnumerator()) 
     { 
      TSource current; 
      TSource nextElement; 

      if (!enumerator.MoveNext()) 
       yield break; 
      while (true) 
      { 
       current = enumerator.Current; 
       if (!enumerator.MoveNext()) 
        yield break; 
       nextElement = enumerator.Current; 

       if (predicate(current) && EqualityComparer<TSource>.Default.Equals(next, nextElement)) 
        yield return current; 
      } 
     } 
    } 
} 

警告:目前使用EqualityComparer<TSource>.Default的比较。应使用自定义比较器的另一个实现。

+0

这有点复杂,但也许是最有效的。 – Peter17 2011-03-05 16:06:46

+0

它也不枚举两次'IEnumerable',这可能是一个优点。 – Femaref 2011-03-05 16:35:37

1

如果集合是stirng的列表,你可以尝试像涉及让利

var selectC = from c in collection 
let nextC = collection.IndexOf(c) == collection.Count - 1 ? null : collection[collection.IndexOf(c) + 1] 
where string.IsNullOrEmpty(c) && string.IsNullOrEmpty(nextC) 
select c; 

查询是棘手转化为方法链,但我得到这个从ReSharper的自动转换

var selectC = 
    collection.Select(
     c => 
     new {c, nextC = collection.IndexOf(c) == collection.Count - 1 ? null : collection[collection.IndexOf(c) + 1]}). 
     Where(@t => string.IsNullOrEmpty(@t.c) && string.IsNullOrEmpty(@t.nextC)).Select(@t => @t.c); 
1

可以使用Aggregate Method创建自定义的总和:

var result = collection.Aggregate(
    Tuple.Create(false, 0), 
    (s, x) => Tuple.Create(x == something, 
          s.Item1 + (s.Item0 && (x == somethingElse) ? 1 : 0)), 
    s => s.Item1); 

它的工作原理是这样的:

 
Item   Accumulator 
--------------- --------------- 
       (false, 0) 
foo    (false, 0) 
something  (true, 0) 
bar    (false, 0) 
something  (true, 0) 
somethingElse (false, 1) 
somethingElse (false, 1) 
baz    (false, 1) 
       --------------- 
       Result: 1 
+0

有趣的实现。 – Peter17 2011-03-05 16:05:54