将通用IEnumerable转换为列表

时间:2013-12-03 11:21:35

标签: c# generics casting ienumerable .net

我正在分割一个(在这个例子中)大约的列表。将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方法尽可能保持通用。问题是如何正确地转换返回值。有人能指出我该怎么做吗?

提前致谢。

3 个答案:

答案 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()都会导致对同一组元素进行不必要的迭代。