2011-10-01 52 views
-2

如果序列中兩個或多個元素在列表中具有相同屬性,我想識別並提取元素。 例如 我有一個列表 有一個名爲IsValid的 現在我想確定是否在序列中的兩個或多個文檔具有的IsValid ==文檔屬性真正 假設結構確定序列中兩個或多個元素是否具有相同屬性

IsValid = false 
IsValid = true 
IsValid = true 
IsValid = false 
IsValid = true 
IsValid = false 

我的查詢應該只返回元素2和3,因爲只有這兩個順序,並且ISvalid = true 我該如何實現它?

回答

0

您只需檢查當前項目是否有效,以及上一個項目是否在同一時間有效。這將捕獲大多數情況,但是如果尚未存儲之前需要確保保留之前的項目。

類似下面的代碼應該做的。請注意,它是從內存寫入的,未經測試,而我不是最有效的方法。

public List<Document> GetConsecutiveTrueDocs(List<Document> list) 
{ 
    var result = new List<Document>(); 

    if(list.Count < 2) 
     return result; 

    for(int i = 1; i < list.Count; i++) 
    { 
     if(list[i].IsValid && list[i-1].IsValid) 
     { 
      if(!result.Contains(list[i-1])) 
       result.Add(list[i-1]); 

      result.Add(list[i]); 
     } 
    } 

    return result; 
} 
1

你可以寫一個簡單的LINQ擴展方法:

public static IEnumerable<IEnumerable<TSource>> 
    ContinuouslyEqualSubSequences<TSource, TResult>(
     this IEnumerable<TSource> source, 
     Func<TSource, TResult> func 
) { 
    var e = source.GetEnumerator(); 
    var currentSequence = default(List<TSource>); 
    var resultOfCurrentSequence = default(TResult); 
    if (e.MoveNext()) { 
     currentSequence = new List<TSource>() { e.Current }; 
     resultOfCurrentSequence = func(e.Current); 
    } 
    while (e.MoveNext()) { 
     var currentResult = func(e.Current); 
     if(Object.Equals(resultOfCurrentSequence, currentResult)) { 
      currentSequence.Add(e.Current); 
     } 
     else { 
      if(currentSequence.Count > 1) { 
       yield return currentSequence; 
      } 
      currentSequence = new List<TSource>() { e.Current }; 
      resultOfCurrentSequence = currentResult; 
      } 
     } 

     if (currentSequence.Count > 1) { 
      yield return currentSequence; 
     } 
    } 

var sequence = new { 3, 4, 7, 8, 9, 2, 4, 6, 0, 1, 1, 17, 2, 3, 2, 20 }; 
var subsequences = sequence.ContinuouslyEqualSubSequences(x => x % 2); 

我找回序列

2 4 6 0 
1 1 17 
2 20 

如預期,因爲我們正在尋找這裏爲奇數o的連續子序列r偶數。

+0

哇。你的「簡單」的定義顯然與我的完全不同! – Gabe

+0

不要將長度與非簡單混爲一談。這個算法*很簡單。從序列中讀取,跟蹤當前的「投影」(我稱它爲resultOfCurrentSequence)。對於你遇到的相同投影的每個後續項目,將它添加到當前的子序列(我稱它爲「currentSequence」)。當遇到不同的東西時,如果長度超過一個,則產生當前的子序列,開始一個新的子序列並用新的投影替換舊的投影。如果到達序列的末尾,並且當前子序列的長度不止一個,則將其退回。 – jason

+0

我不是說你的*算法不簡單,只是代碼不是(我不是說你的代碼有什麼問題)。在22行中,它包含了對構造函數,方法和屬性的14次調用,加上4個'if's和'while' - 這就忽略了缺少'using'來處理枚舉數。而且,返回一系列序列並不像返回一個平坦序列那麼簡單。我的解決方案縮短了幾行,沒有構造函數/方法/屬性調用,但它仍然不是我認爲的「簡單」。 – Gabe

0

下面是一個相對簡單的擴展方法,它的來源序列,並告訴任何兩個元素是否被視爲相等的功能,並返回元素的一個序列:

public static IEnumerable<T> Consecutives<T>(this IEnumerable<T> source, 
              Func<T, T, bool> equals) 
{ 
    T last = default(T); 
    bool first = true; 
    bool returnedLast = false; 
    foreach (T current in source) 
    { 
     if (!first && equals(current, last)) 
     { 
      if (!returnedLast) 
       yield return last; 
      returnedLast = true; 
      yield return current; 
     } 
     else 
      returnedLast = false; 
     first = false; 
     last = current; 
    } 
} 

如果用

嘗試
var sequence = new[] { 3, 4, 7, 8, 9, 2, 4, 6, 0, 1, 1, 17, 2, 3, 2, 20 }; 
var subsequences = sequence.Consecutives((x, y) => x % 2 == y % 2); 

你將得到: 2 4 6 0 1 1 17 2 20

如果你的序列不具有任何重複,T他雷蒙德的解決方案的擴展是效率低下,而且很簡單:

public static IEnumerable<T> Consecutives<T>(this IEnumerable<T> source, 
              Func<T, T, bool> equals) 
{ 
    return source.Zip(source.Skip(1), (x, y) => new[] { x, y }) 
       .Where(d => equals(d[0], d[1])) 
       .SelectMany(d => d) 
       .Distinct(); 
} 
0

這可以通過自身的偏移版本荏苒序列減少到一個班輪。

public static IEnumerable<Tuple<TSource,TSource>> 
    Consecutives<TSource>(this IEnumerable<TSource> source, 
          Func<TSource, TSource, bool> equals) 
{ 
    return source.Zip(source.Skip(1), (x, y) => Tuple.Create(x,y)) 
       .Where(d => equals(d.Item1, d.Item2)); 
} 
+0

這聽起來像OP想要一個'IEnumerable '作爲結果,並且不清楚如何從你的函數的'IEnumerable >'得到它。 – Gabe

+0

如果連續有三個真實的項目,OP的要求是不明確的。他們想要(2,3,3,4)還是隻需要(2,3,4)?對於前者,做一個SelectMany。對於後者,添加一個唯一。 –

+0

好的,但'Tuple'上的'SelectMany'沒有任何意義。也許你想要一個數組? – Gabe

相關問題