2012-03-01 20 views
2

我正在爲製造公司創建應用程序。我們正在實施WECO(Western Electric Co.)統計過程控制規則。其中一條規則規定,如果連續3個值中有2個值超過某個目標值,則發出警報。Linq Query需要滿足WECO規則

所以,讓事情變得簡單,說我有以下值的列表:

List<double> doubleList = new List<double>() 
{ 
     .89,.91,.93,.95,1.25,.76,.77,.78,.77,1.01,.96,.99, .88,.88,.96,.89,1.01 
}; 

從這個名單,我想拉出來,其中任何2出3個連續的值大於所有序列。 94。 Linq查詢應返回以下六個序列:

.93, .95, 1.25 (3rd, 4th and 5th values) 
.95, 1.25, .76 (4th, 5th and 6th values) 
.77, 1.01, .96 (9th, 10th and 11th values) 
1.01, .96, .99 (10th, 11th and 12th values) 
.96, .99, .88 (11th, 12th and 13th values) 
.96, .89, 1.01 (15th, 16th and 17th values) 

注意最後一個序列。這三個值中的兩個值不是連續的。沒關係,他們不需要。只有3個連續的2個。

我想過與第一值開始,採取三個檢查任何兩個指出,三,移動到第二值,做同樣的,移動到第三和循環做同樣的等等。這當然會起作用,但會很慢。我假設必須有一個更快的方法來做到這一點。

回答

4

你可以寫一個擴展方法:

public static IEnumerable<IEnumerable<double>> GetTroubleSequences(this IEnumerable<double> source, double threshold) 
{ 
    int elementCount = source.Count(); 
    for (int idx = 0; idx < elementCount - 2; idx++) 
    { 
     var subsequence = source.Skip(idx).Take(3); 
     if (subsequence.Aggregate(0, (count, num) => num > threshold ? count + 1 : count) >= 2) 
     { 
      yield return subsequence.ToList(); 
     } 
    } 
} 

現在你可以使用它你的輸入列表中:

var problemSequences = doubleList.GetTroubleSequences(0.94); 

需要注意的是上述的擴展方法是低效的,如果你的輸入列表是非常長你應該考慮只是一個滑動窗口的循環規律,因此您只能在序列重複一次 - 或相應重寫擴展方法(即限制ICollection輸入,因此你可以使用,而不必使用Skip的索引d Take)。

更新:

這裏需要IList所以我們可以使用索引版本:

public static IEnumerable<IEnumerable<double>> GetTroubleSequences(this IList<double> source, double threshold) 
{ 
    for (int idx = 0; idx < source.Count - 2; idx++) 
    { 
     int count = 0; 
     for (int i = idx; i < idx + 3; i++) 
      if (source[i] > threshold) 
       count++; 
     if (count >= 2) 
      yield return new[] { source[idx], source[idx + 1], source[idx + 2] }; 
    } 
} 

這個版本是一次遍歷列表,列表中的每個項目評估未來3個項目啓動與目前的項目,所以仍然爲O(n)。

+0

我不知道你是否曾在此了,但如果序列中的最後兩個值低,那麼你就需要計算下一個號碼,你可以跳過後,下一個。 – Niklas 2012-03-01 15:39:51

0

您可以通過使用Enumerable.Zip擴展方法做到這一點:

var result = doubleList 
    .Zip(doubleList.Skip(1), (first, second) => new[] { first, second }) 
    .Zip(doubleList.Skip(2), (temp, third) => new[] { temp[0], temp[1], third }) 
    .Where(i => i.Count(d => d > .94) >= 2); 

我想提一提,這方法也效率低下。這只是嘗試通過使用LINQ來實現它。

相關問題