我有一个观察清单,想要找到给定计数的连续交替上下值。例如,当观察列表为{ 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;
}
答案 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);
这会将observations
与observations-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
所以有:
runs => { {0, 2}, {1, 6}, {6, 4}, {9, 2} }
{ 1, 3 }
{ 3, 4, 2, 7, 5, 6 }
{ 6, 8, 1, 2 }
希望这有帮助