我正在分割一个(在这个例子中)大约的列表。将190000件物品装入5000件物品中。
所以代替:List<Object>
,计算190000
它变为:List<List<Object>>
,计数28(计数5000))
我使用以下代码执行此操作:
public static IEnumerable<List<Object>> Split(this IEnumerable<Object> sourceList, int chunkSize)
{
int numberOfLists = (sourceList.Count() / chunkSize) + 1;
List<List<Object>> result = new List<List<object>>();
for (int i = 0; i < numberOfLists; i++)
{
List<Object> subList = new List<Object>();
subList = sourceList.Skip(i * chunkSize).Take(chunkSize).ToList();
result.Add(subList);
}
return result;
}
我将此方法(驻留在辅助类中)调用如下;
var chunkList = (IEnumerable<List<MyObjectClass>>)MyHelper.Split(myObjectList, 5000);
在上面的行中,我显式地转换了列表,该列表在InvalidCastException中失败。当我使用as运算符时,如下所示;
var chunkList = MyHelper.Split(myObjectList, 5000) as IEnumerable<List<MyObjectClass>>;
结果为空。
我预计我可以使用
List<List<MyObjectClass>> chunkList = MyHelper.Split(myObjectList, 5000) as List<List<MyObjectClass>>
我希望将splitter方法尽可能保持通用。问题是如何正确地转换返回值。有人能指出我该怎么做吗?
提前致谢。
答案 0 :(得分:2)
您可以使用type参数而不是object
public static IEnumerable<List<T>> Split<T>(this IEnumerable<T> sourceList, int chunkSize) {
int numberOfLists = (sourceList.Count() / chunkSize) + 1;
List<List<T>> result = new List<List<T>>();
for (int i = 0; i < numberOfLists; i++)
{
result.Add(sourceList.Skip(i * chunkSize).Take(chunkSize));
}
return result;
}
所以使用
IEnumerable<List<MyObjectClass>> chunkList = myObjectClassList.Split(5000);
答案 1 :(得分:2)
正如其他人所说,问题在于您尝试以变体方式使用类型参数或List<T>
,这是不可能的。而不是这个,你需要使分裂方法通用,以便它有自己的类型参数匹配列表的类型参数。
也就是说,您可以将方法转换为迭代器块,以便它只按需生成子列表:
public static IEnumerable<List<T>> Partition<T>(this IEnumerable<T> source,
int chunkSize)
{
while (source.Any())
{
yield return source.Take(chunkSize).ToList();
source = source.Skip(chunkSize);
}
}
这将用作
var chunkList = sourceList.Partition(5000);
请注意,上述版本不含原始代码及基于它的解决方案共享的off-by-one error。
如果您不关心延迟评估,还可以使用GroupBy
这个技巧进行分区:
int i = 0;
var chunkList = sourceList
.GroupBy(o => i++ / chunkSize) // group into partitions
.Select(Enumerable.ToList) // transform each partition into a List
.ToList() // force evaluation of query right now
答案 2 :(得分:1)
而不是将IEnumerable<Object>
作为参数并返回IEnumerable<List<Object>>
,而不是将您的方法设为通用:
public static IEnumerable<List<T>> Split<T>(this IEnumerable<T> sourceList, int chunkSize)
{
int numberOfLists = (sourceList.Count() / chunkSize) + 1;
var result = new List<List<T>>(numberOfLists);
for (int i = 0; i < numberOfLists; i++)
{
result.Add(sourceList.Skip(i * chunkSize).Take(chunkSize).ToList());
}
return result;
}
您还可以使用moreLINQ库中的Partition
方法。它比您的解决方案更有效,因为每次使用Skip().Take()
都会导致对同一组元素进行不必要的迭代。