我有一个C#队列<TimeSpan> 含有500个单元。

我需要降低这些成50元素通过把10人以上的团体时间跨度,并选择他们的平均水平。

是否有一个清洁的方式来做到这个吗?我想到皇宫会有所帮助,但是我不能找出一个清洁的方式。任何想法?

有帮助吗?

解决方案

我会使用组块的功能和一个循环。

foreach(var set in source.ToList().Chunk(10)){
    target.Enqueue(TimeSpan.FromMilliseconds(
                            set.Average(t => t.TotalMilliseconds)));
}

块是我的标准辅助库的一部分。 http://clrextensions.codeplex.com/

来源为组块

其他提示

看一看的 .Skip()和。取()扩展方法,您的队列划分成集。然后,您可以使用。平均(T => t.Ticks)来获取代表平均新的时间跨度。只是堵塞那些每50周均线成一个新的队列,你是好去。

Queue<TimeSpan> allTimeSpans = GetQueueOfTimeSpans();
Queue<TimeSpan> averages = New Queue<TimeSpan>(50);
int partitionSize = 10;
for (int i = 0; i <50; i++) {
    var avg = allTimeSpans.Skip(i * partitionSize).Take(partitionSize).Average(t => t.Ticks)
    averages.Enqueue(new TimeSpan(avg));
}

我是VB.NET的人,所以可能存在一些语法不在该示例100%的写入。让我知道,我会解决它!

也许没有什么比在这种情况下,一个方法调用一个很好的旧程序的执行。这不是幻想,但它很容易,并且可以通过小级别的开发者进行维护。

public static Queue<TimeSpan> CompressTimeSpan(Queue<TimeSpan> original, int interval)
{
    Queue<TimeSpan> newQueue = new Queue<TimeSpan>();
    if (original.Count == 0) return newQueue;

    int current = 0;
    TimeSpan runningTotal = TimeSpan.Zero;
    TimeSpan currentTimeSpan = original.Dequeue();

    while (original.Count > 0 && current < interval)
    {
        runningTotal += currentTimeSpan;
        if (++current >= interval)
        {
            newQueue.Enqueue(TimeSpan.FromTicks(runningTotal.Ticks / interval));
            runningTotal = TimeSpan.Zero;
            current = 0;
        }
        currentTimeSpan = original.Dequeue();
    }
    if (current > 0)
        newQueue.Enqueue(TimeSpan.FromTicks(runningTotal.Ticks / current));

    return newQueue;
}

您可以只使用

static public TimeSpan[] Reduce(TimeSpan[] spans, int blockLength)
{
    TimeSpan[] avgSpan = new TimeSpan[original.Count / blockLength];

    int currentIndex = 0;

    for (int outputIndex = 0;
         outputIndex < avgSpan.Length; 
         outputIndex++)
    {
        long totalTicks = 0;

        for (int sampleIndex = 0; sampleIndex < blockLength; sampleIndex++)
        {
            totalTicks += spans[currentIndex].Ticks;
            currentIndex++;
        }

        avgSpan[outputIndex] =
            TimeSpan.FromTicks(totalTicks / blockLength);
    }

    return avgSpan;
}

这是一个小更详细的(它不使用LINQ),但它是很容易看到它在做什么......(您可以在队列向/从阵列很容易地)

我会使用一个循环,但只是为了好玩:

IEnumerable<TimeSpan> AverageClumps(Queue<TimeSpan> lots, int clumpSize)
{
    while (lots.Any())
    {
        var portion = Math.Min(clumpSize, lots.Count);
        yield return Enumerable.Range(1, portion).Aggregate(TimeSpan.Zero,
            (t, x) => t.Add(lots.Dequeue()),
            (t) => new TimeSpan(t.Ticks / portion));
        }
    }
}

这仅检查每个元件一次,所以性能比其他LINQ产品好得多。不幸的是,变异的队列,但也许这是一个功能,而不是一个错误?

它确实有被一个迭代的不错的奖金,所以它给你的平均一次一个。

与整数(0..N)一起正在压缩它,并通过序列号的div 10分组?

我不是一个LINQ用户,但我相信它会是这个样子:

for (n,item) from Enumerable.Range(0, queue.length).zip(queue) group by n/10

在取(10)的解决方案是可能会更好。

是如何分组会执行?

假定很简单的东西(需要10时),就可以开始喜欢的东西:

List<TimeSpan> input = Enumerable.Range(0, 500)
                                 .Select(i => new TimeSpan(0, 0, i))
                                  .ToList();

var res = input.Select((t, i) => new { time=t.Ticks, index=i })
               .GroupBy(v => v.index / 10, v => v.time)
               .Select(g => new TimeSpan((long)g.Average()));

int n = 0;
foreach (var t in res) {
    Console.WriteLine("{0,3}: {1}", ++n, t);
}

注:

  • 载的选择,以获得的索引,然后使用这整数和分捡团的10.可以使用的模采取一切10日元为一组,每10+1到另一个...
  • 结果的分组是一个顺序的枚举的一个关键的财产。但需要的只是那些单独的序列在这里。
  • 有没有可枚举的。平均超负荷 IEnumerable<TimeSpan> 因此,使用蜱(a长)。

编辑:采取组10到更适合的问题。
EDIT2:现在测试的代码。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top