C# 保持x个数字的平均值,同时继续添加

C# 保持x个数字的平均值,同时继续添加,c#,arrays,C#,Arrays,我需要保持一个滚动平均值。我需要说,在一个数组中有10个数字(或者其他什么?),然后继续添加到这个数组中,得到这些数字的平均值 我有一个程序,每秒钟会得到一个数字,并将其添加到列表中。然后我需要列表中最后x个数字的平均值。还需要限制列表中的数量,以便内存不会填满,因为它将每秒添加数字 有人能帮忙吗?我不知道从哪里开始 eg阵列10,9,8,7,6,5,4,3,2,1平均值=5.5 加上下一个数字11,10,9,8,7,6,5,4,3,2平均值=6.5 等等, 数组只需是添加到数组中的最后10个数

我需要保持一个滚动平均值。我需要说,在一个数组中有10个数字(或者其他什么?),然后继续添加到这个数组中,得到这些数字的平均值

我有一个程序,每秒钟会得到一个数字,并将其添加到列表中。然后我需要列表中最后x个数字的平均值。还需要限制列表中的数量,以便内存不会填满,因为它将每秒添加数字

有人能帮忙吗?我不知道从哪里开始

eg阵列10,9,8,7,6,5,4,3,2,1平均值=5.5

加上下一个数字11,10,9,8,7,6,5,4,3,2平均值=6.5

等等,


数组只需是添加到数组中的最后10个数字

您可以使用通用列表。在计算最后10个元素的平均值时,请确保检查它是否实际包含至少10个元素

var list = new List<int>();
list.Add(5);
//....
var average = list.Skip(list.Count - 10).Average();
var list=newlist();
增加(5);
//....
var average=list.Skip(list.Count-10.average();

如果需要最后一个
x
数字的平均值,请创建一个
x
值数组,并将其用作

除了缓冲区之外,还要保留运行总数。当一个新的数字进来时,看看你的循环缓冲区是否被填满了。如果是,则在添加新收到的号码之前,从运行总数中减去最后一个号码


这将使您可以在O(1)时间而不是O(x)时间内计算新的平均值,即计算时间将与平均的项数无关。

我将使用链表进行计算。这使得列表管理简单且“低成本”。调整大多数其他类型容器的大小可能需要对内存中的数据进行洗牌。从前端删除是LinkedList的优势所在

//make a linked list and fill it...
LinkedList<int> list = new LinkedList<int>(Enumerable.Repeat(0,10));

list.AddLast(0);
while(list.Count > 10)
{
    list.RemoveFirst();
}
var avg = list.Average();
//制作一个链表并填充它。。。
LinkedList=新的LinkedList(可枚举。重复(0,10));
list.AddLast(0);
而(list.Count>10)
{
list.RemoveFirst();
}
var avg=list.Average();

如果数组与示例中的数组相似,您可以简单地观察到,每次在数组的一端添加一个新数字,并从另一端删除一个数字时,平均值会增加1。因此,您根本不需要该数组——只需将5.5添加到
i

对于
i=0

(10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1) / 10 = 5.5 = 5.5 + i
对于
i=1

(11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2) / 10 = 6.5 = 5.5 + i
对于
i=2

(12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3) / 10 = 7.5 = 5.5 + i

。。。(你明白了)

你可以很容易地用列表而不是数组来实现这一点

只需检查列表是否比您想要的大,然后让它从列表中删除第一项

List<int> Numbers = new List<int>();
if (Numbers.Count > 10)
{
    Numbers.RemoveRange(0, 0);
}
Numbers.Add(11);
var NewAverage = Numbers.Average();
列表编号=新列表();
如果(number.Count>10)
{
数字。删除范围(0,0);
}
增加(11);
var NewAverage=Numbers.Average();

array.Reverse().Take(10).Average()
这是一个家庭作业吗?@TimSchmelter
Reverse
的实现复制了整个输入序列,即使它是一个集合。@Rawling:谢谢你的提示。为什么会这样?它可以检查集合是否已经实现了
IList
@TimSchmelter,我不确定<代码>反向使用
缓冲区
缓冲区
复制整个序列。如果基础集合发生变化,可能他们也会坚持复制
IList
s以保持一致性?我认为你的
Skip
实际上更有效-C#知道
Skip
可以在处理列表时跳转到正确的项,但是
Reverse
仍然必须复制整个列表,才能只获取其中的10个项目。@罗琳:不要跳转到正确的项目,它还会枚举整个序列,直到达到所需的项目为止。但你是对的,它在内存消耗方面更有效,因为它不需要将整个内容复制到像
可枚举的新集合中。相反的
可以。@TimSchmelter是的,我认为
跳过
会优化
IList
。看起来我们对LINQ对象的期望都比实际得到的要高@OP:实际上,您不需要确保它至少包含10个元素。如果将负值或0传递给可枚举。跳过将返回整个序列。因此,您的实现已经是安全的。@TimSchmelter但是,如果要跳过的参数大于列表中的元素数量,则返回一个空IEnumerable:调用Average()会引发InvalidOperationException。@如果事先不知道
x
,则最好选择spender链表。但是,当您知道
x
时,普通数组会让您与.NET中的数组一样“接近金属”,因为您实际上不会得到任何开销—在内存使用、缓存性能、CPU指令数等方面。计算平均值相对昂贵。OP应该保留一个sum变量。然后添加新值,减去RemoveFirst()处的值,并计算平均值作为总和/count@DrKoch超过10个值?除非这是一个性能热点,否则我不会再深入研究了……当然,有10个值,这是一个玩具示例。但我发现这很有趣:原则上,滚动平均可以是O(1)运算,而不是O(N)with.average()(参见dasblinkenlight的答案)