Linq Query需要满足WECO规则

时间:2012-03-01 15:00:23

标签: linq

我正在为制造公司创建一个应用程序。我们正在实施WECO(Western Electric Co.)统计过程控制规则。其中一条规则规定,如果3个连续值中的任何2个超过某个目标值,则发出警报。

所以,为了简单起见,请说我有以下值列表:

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
};

从这个列表中,我想拉出所有序列,其中3个连续值中的任何2个都大于.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次。

我考虑从第一个值开始,取三个并检查三个中的任何两个,移动到第二个值,做同样的事情,移动到第三个并在循环中执行相同的操作等当然会工作,但会很慢。我假设必须有更快的方法来做到这一点。

2 个答案:

答案 0 :(得分: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);

请注意,上面的扩展方法效率很低,如果您的输入列表很长,您应该只考虑带有滑动窗口的常规for循环,这样您只需迭代序列一次 - 或相应地重写扩展方法(即限制为{ {1}}输入,因此您可以使用索引器,而不必使用ICollectionSkip)。

更新

这是一个需要Take的版本,因此我们可以使用索引器:

IList

这个版本遍历列表一次,对于列表中的每个项目,评估从当前项目开始的下3个项目,所以仍然是O(n)。

答案 1 :(得分: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来实现它。