2011-03-05 189 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