我正在处理尝试在C#2.0中实现IEnumerable(和ICollection)的自定义集合类中的块。比方说,例如,我一次只需要1000个项目,而我的收藏中有3005个项目。我有一个工作解决方案,我在下面演示,但它看起来很原始,我认为必须有一个更好的方法来做到这一点。
这就是我所拥有的(例如,我使用的是C#3.0的Enumerable和var,只需将这些引用替换为您心目中的自定义类):
var items = Enumerable.Range(0, 3005).ToList();
int count = items.Count();
int currentCount = 0, limit = 0, iteration = 1;
List<int> temp = new List<int>();
while (currentCount < count)
{
limit = count - currentCount;
if (limit > 1000)
{
limit = 1000 * iteration;
}
else
{
limit += 1000 * (iteration - 1);
}
for (int i = currentCount; i < limit; i++)
{
temp.Add(items[i]);
}
//do something with temp
currentCount += temp.Count;
iteration++;
temp.Clear();
}
任何人都可以在C#2.0中建议更优雅的方式吗?我知道这个项目是否来自过去5年,我可以使用Linq(如所示here和here)。我知道我的方法会起作用,但我不想让我的名字与这种丑陋的(在我看来)代码相关联。
感谢。
答案 0 :(得分:8)
首先。 yield
在这里是你的朋友,它是2.0引入的。考虑:
public static IEnumerable<List<T>> Chunk<T>(IEnumerable<T> source, int chunkSize)
{
List<T> list = new List<T>(chunkSize);
foreach(T item in source)
{
list.Add(item);
if(list.Count == chunkSize)
{
yield return list;
list = new List<T>(chunkSize);
}
}
//don't forget the last one!
if(list.Count != 0)
yield return list;
}
然后我们在类型和大小上都很灵活,所以它可以很好地重复使用。唯一被限制为2.0意味着,我们不能将其作为一种扩展方法。
答案 1 :(得分:2)
有几种方法可以解决这个问题。
如果您只想将每个项目与其所属的块的索引相关联:
int processed = 0;
foreach (int item in items)
{
int chunkIndex = processed++ / CHUNK_SIZE;
ProcessItem(item, chunkIndex);
}
如果要批量处理项目,但不一次需要整个块集合:
int processed = 0, count = items.Count;
List<int> chunk = new List<int>(CHUNK_SIZE);
foreach (int item in items)
{
chunk.Add(item);
if (++processed % CHUNK_SIZE == 0 || processed == count) {
ProcessChunk(chunk);
chunk.Clear();
}
}
如果您想将所有块作为列表列表:
int processed = 0, count = items.Count;
List<List<int>> chunks = new List<List<int>>();
foreach (int item in items)
{
int chunkIndex = processed++ / CHUNK_SIZE;
if (chunks.Count == chunkIndex) {
chunks.Add(new List<int>(CHUNK_SIZE));
}
chunks[chunkIndex].Add(item);
}