在列表中上下交替的连续点

时间:2018-02-09 08:17:36

标签: c#

我有一个观察清单,想要找到给定计数的连续交替上下值。例如,当观察列表为{ 1, 3, 4, 2, 7, 5, 6, 8, 1, 2, 4}且给定的检查计数为4时,方法应返回list<list>>作为{{3,4,2,7}, {2,7,5,6}}

我已经创建了如下方法,但是想用linq或更高效的方式来做这件事。有人可以帮忙吗?

List<List<decimal>> GetinvalidObservationMatrix(List<decimal> observationList, int checkedCount)
    {
        List<List<decimal>> invalidObservationMatrix = new List<List<decimal>>();

        while (observationList.Count >= checkedCount)
        {
            List<decimal> currentObservationList = observationList.Take(checkedCount).ToList();
            bool isGreater = false;
            bool isPreviousGreater = false;

            for (int i = 1; i < checkedCount - 1; i++)
            {
                isPreviousGreater = isGreater;

                if (currentObservationList[i] == currentObservationList[i - 1] || currentObservationList[i] == currentObservationList[i + 1])
                {
                    break;
                }

                if (currentObservationList[i] > currentObservationList[i - 1])
                {
                    isGreater = true;
                }
                else
                {
                    isGreater = false;
                }

                if (i != 1 && isGreater == isPreviousGreater)
                {
                    break;
                }

                if (isGreater)
                {
                    if (currentObservationList[i + 1] >= currentObservationList[i])
                    {
                        break;
                    }
                }
                else
                {
                    if (currentObservationList[i + 1] <= currentObservationList[i])
                    {
                        break;
                    }
                }

                if (i == checkedCount - 2)
                {
                    invalidObservationMatrix.Add(currentObservationList);
                }
            }

            observationList = observationList.Skip(1).ToList();
        }

        return invalidObservationMatrix;
    }

1 个答案:

答案 0 :(得分:0)

接受这实际上没有回答原始问题,此代码将找到所有交替序列。

void FindAlternativeSequences()
{
    var observations = new List<int>() { 1, 3, 4, 2, 7, 5, 6, 8, 1, 2, 4 };
    const int threshold = 4;

    var consecutivePairs = observations.Skip(1).Zip(observations, (a, b) => Math.Sign(a - b)).Zip(GetAlternator(), (x, y) => x * y);
    var runs = FindEqualRuns(consecutivePairs).Select(t => new Tuple<int, int>(t.Item1, t.Item2 + 1)).ToList();
}

public IEnumerable<int> GetAlternator()
{
    int value = -1;
    int sanity = Int32.MaxValue;
    while (--sanity > 0)
    {
        value *= -1;
        yield return value;
    }
    yield break;
}

public IEnumerable<Tuple<int,int>> FindEqualRuns(IEnumerable<int> enumerable)
{
    int previousValue = 0;
    int index = 0;
    int startIndex = 0;
    bool foundAnElement = false;

    foreach ( var value in enumerable )
    {
        if (index == 0) previousValue = value;
        foundAnElement = true;

        if (!value.Equals(previousValue))
        {
            // This is a difference, return the previous run
            yield return new Tuple<int, int>(startIndex, index - startIndex);
            startIndex = index;
            previousValue = value;
        }

        index++;
    }

    if (foundAnElement)
    {
        yield return new Tuple<int, int>(startIndex, index - startIndex);
    }

    yield break;
}

它的作用

代码查找任何长度的所有交替序列,从向上步骤或向下步骤开始。然后它使用元组填充runs变量,其中Item1是序列中第一个元素的索引,Item2是交替序列的长度。

然后可以使用此runs变量来询问有关数据的各种问题,例如得出原始问题的答案。 runs输出本身不会返回交替序列,但会识别它们的位置和长度。

工作原理

大部分工作都在一行中完成:

var consecutivePairs = observations.Skip(1).Zip(observations, (a, b) => Math.Sign(a - b)).Zip(GetAlternator(), (x, y) => x * y);

这会将observationsobservations-skip-1一起拉链,以提供成对的连续值。然后将这些对减去并运行Math.Sign()函数,以便{1}},+1-1得出第一个是更大,第二个是更大,还是它们是相同。此输出具有0+1的运行,用于增加或减少序列。它也是一个比-1短的元素。

observations

然后将此结果压缩并乘以交替的observations => { 1, 3, 4, 2, 7, 5, 6, 8, 1, 2, 4 } Output from 1st .Zip() => { 1, 1, -1, 1, -1, 1, 1, -1, 1, 1 } 序列。这导致+1或-1的运行,表示连续的上行和下行步骤。

+1, -1, +1, -1, ...

然后,行observations => { 1, 3, 4, 2, 7, 5, 6, 8, 1, 2, 4 } Output from 1st .Zip() => { 1, 1, -1, 1, -1, 1, 1, -1, 1, 1 } Output from 2nd .Zip() => { 1, -1, -1, -1, -1, -1, 1, 1, 1, -1 } 使用另一个函数来查找该集合中的所有连续运行或+1,-1或0,给出var runs = FindEqualRuns(consecutivePairs).Select(t => new Tuple<int, int>(t.Item1, t.Item2 + 1)).ToList();startIndex。因为这给了我们针对对枚举(比原始count短一个元素)的运行,我们需要为每个计数加1。例如,如果它在对枚举中找到3个元素的运行,则表示在observations中运行4个元素。

observations中的输出给出了数据中所有交替序列的起点和长度的详细信息。

runs

所以有:

  • 长度为2的序列,从第0个索引开始=&gt; runs => { {0, 2}, {1, 6}, {6, 4}, {9, 2} }
  • 长度为6的序列,从第1个索引开始=&gt; { 1, 3 }
  • 长度为4的序列,从第6个索引开始=&gt; { 3, 4, 2, 7, 5, 6 }
  • 长度为2的序列,从第9个索引开始=&gt; { 6, 8, 1, 2 }

希望这有帮助