2

我有一个排序Listints (按降序排列),我需要重新排序,以便每个批次(例如 20 秒)具有int彼此尽可能远的 s。

因此,例如,如果列表包含以下预订:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

我要分批处理 4 个,一个好的方法是将预订分成 4 个列表(12 / 3),然后向下移动每个 4 个列表,每个列表取 1 个并附加到新创建的重新排序列表? 因此,新列表将按以下顺序包含预订:

  • 1
  • 5
  • 9
  • 2
  • 6
  • 10
  • 3
  • 7
  • 11
  • 4
  • 8
  • 12

我很高兴理解我的问题所追求的并不容易,因此查看我的代码可能会更容易!我想出了以下方法,并想知道它是否是实现我所追求的最佳/最高效的方法:

var bookings = new List<int>();

// <snip>import bookings ints from csv file into bookings list</snip>

bookings = bookings.Distinct().OrderByDescending(x => x).ToList();

int chunkSize = 20;

// get number of chunks/batches
int chunkCount = (int)Math.Ceiling((double)bookings.Count/(double)chunkSize);

// split booking list into number of chunks
// add the ith booking from each chunk into new list
// ToChunks() extension method from http://stackoverflow.com/a/6852288/1578713
var chunkList = bookings.ToChunks(chunkCount).ToList();
var reorderedBookings = new List<int>();
for (int i=0; i<chunkCount; i++)
{
    // last chunk may be smaller than chunkSize hence the check
    reorderedBookings.AddRange(from chunk in chunkList where chunk.Count() > i 
        select chunk.ToList()[i]);
}

bookings = reorderedBookings;

背景(如果你真的想知道)

我的问题是我正在处理* a Listof ints (从 csv 文件导入并订购的预订)并行批次(例如 20 个)并且这些预订在列表中越靠近(越连续)越有可能就是会抛出异常(超出我的控制范围)。

这是在同步运行数千个预订(因此不会引发异常)或并行运行 20 多个预订之间进行权衡,并有可能每隔一段时间就引发一次所述异常。我选择了后一种方法,因为它更快,并且任何导致异常的预订都可以在异步任务完成后同步运行。

*调用几个服务,int依次传递每个预订

4

2 回答 2

1

好的,所以它相当简单:

public static IEnumerable<IEnumerable<T>> BatchAndSeparate<T>(IList<T> source, int batchSize)
{
    int numBatches = (int)Math.Ceiling(source.Count / (double)batchSize);

    for (int i = 0; i < numBatches; i++)
    {
        var buffer = new List<T>();
        for (int j = i; j < source.Count; j += numBatches)
        {
            buffer.Add(source[j]);
        }
        yield return buffer;
    }
}

一般算法是,对于每个批次,您的索引都以该批次的编号(零索引)开始,并在每次迭代中添加批次数。

它可以像这样使用:

var batches = BatchAndSeparate(Enumerable.Range(1, 13).ToList(), 3);

foreach (var batch in batches)
{
    Console.WriteLine(string.Join(" ", batch));
}

这将打印:

1 6 11
2 7 12
3 8 13
4 9
5 10

当以这种方式显示时,很容易看出它是正确的。顺着每一列往下看,数字加一,然后从最左边的那一列向右移动。

于 2012-11-28T18:24:40.057 回答
1

假设 Servy 对你想要的东西是正确的,你可以这样做

int i = 0;
var grouped = bookings.OrderBy(x => (i++) % chunkSize);

或者

int i = 0;
var grouped = bookings.GroupBy(x => (i++) % chunkSize);

第一个会给你一个单独的列表,第二个会把它分成单独的列表。

于 2012-11-28T18:30:07.277 回答