Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何有效地拆分具有不同块大小的列表?_C#_.net_Linq_Extension Methods - Fatal编程技术网

C# 如何有效地拆分具有不同块大小的列表?

C# 如何有效地拆分具有不同块大小的列表?,c#,.net,linq,extension-methods,C#,.net,Linq,Extension Methods,我使用以下扩展方法将列表拆分为具有不同块大小的列表,但我怀疑它的效率。我能做些什么来改进它,或者它现在还可以吗 public static List<List<T>> Split<T>(this List<T> source, params int[] chunkSizes) { int totalSize = chunkSizes.Sum(); int sourceCount = source.Count(); if (t

我使用以下扩展方法将
列表
拆分为具有不同块大小的
列表
,但我怀疑它的效率。我能做些什么来改进它,或者它现在还可以吗

public static List<List<T>> Split<T>(this List<T> source, params int[] chunkSizes)
{
    int totalSize = chunkSizes.Sum();
    int sourceCount = source.Count();
    if (totalSize > sourceCount)
    {
        throw new ArgumentException("Sum of chunk sizes is larger than the number of elements in source.", "chunkSizes");
    }

    List<List<T>> listOfLists = new List<List<T>>(chunkSizes.Length);
    int index = 0;
    foreach (int chunkSize in chunkSizes)
    {
        listOfLists.Add(source.GetRange(index, chunkSize));
        index += chunkSize;
    }

    // Get the entire last part if the total size of all the chunks is less than the actual size of the source
    if (totalSize < sourceCount)
    {
        listOfLists.Add(source.GetRange(index, sourceCount - totalSize));
    }

    return listOfLists;
}
公共静态列表拆分(此列表源,参数int[]chunksize)
{
int totalSize=chunkSizes.Sum();
int sourceCount=source.Count();
如果(totalSize>sourceCount)
{
抛出新ArgumentException(“块大小之和大于源中的元素数。”,“块大小”);
}
List listOfLists=新列表(chunkSizes.Length);
int指数=0;
foreach(int chunkSize in chunkSize)
{
Add(source.GetRange(index,chunkSize));
索引+=块大小;
}
//如果所有块的总大小小于源的实际大小,则获取整个最后一部分
if(totalSize
代码用法示例:

List<int> list = new List<int> { 1,2,4,5,6,7,8,9,10,12,43,23,453,34,23,112,4,23 };
var result =  list.Split(2, 3, 3, 2, 1, 3);
Console.WriteLine(result);
List List=新列表{1,2,4,5,6,7,8,9,10,12,43,23453,34,23112,4,23};
var结果=列表分割(2,3,3,2,1,3);
控制台写入线(结果);
这会得到所需的结果,并且最终的列表部分有4个数字,因为总块大小比我的列表大小小4

我特别怀疑
GetRange
部分,因为我担心这只是一次又一次地枚举同一个源


编辑:我想我知道一种枚举源代码的方法:只需对源代码本身执行foreach,并不断检查迭代元素的数量是否与当前chunksize相同。如果是这样,添加新列表并转到下一个chunksize。想法?

此代码没有性能问题。被记录为O(chunkSize),这也很容易推断,因为
列表
最重要的属性之一就是它允许O(1)索引

也就是说,您可以编写一个更LINQ-y版本的代码,如下所示:

var rangeStart = 0;
var ranges = chunkSizes.Select(n => Tuple.Create((rangeStart += n) - n, n))
                       .ToArray();
var lists = ranges.Select(r => source.GetRange(r.Item1, r.Item2)).ToList();

if (rangeStart < source.Count) {
    lists.Last().AddRange(source.Skip(rangeStart));
}

return lists;
var rangeStart=0;
var ranges=chunksize.Select(n=>Tuple.Create((rangeStart+=n)-n,n))
.ToArray();
var list=ranges.Select(r=>source.GetRange(r.Item1,r.Item2)).ToList();
if(rangeStart
我建议使用此扩展方法按指定的块大小将源列表分块到子列表:

using System.Collections.Generic;
using System.Linq;

//
///列表的帮助器方法。
/// 
公共静态类ListExtensions
{
公共静态列表ChunkBy(此列表源,int chunkSize)
{
返回源
.Select((x,i)=>new{Index=i,Value=x})
.GroupBy(x=>x.Index/chunkSize)
.Select(x=>x.Select(v=>v.Value).ToList())
.ToList();
}
}

因为您的输入是一个列表,而不是一个
IEnumerable
,所以您不必担心重复枚举它
Count()。你根本没有列举它!最好使用“收益率-收益率”和“收益率-IEnumerable”。这将允许在调用代码需要时创建块@Davio:是的。我刚刚添加了一个你可能想查看的更为精简的方法。谢谢,我会暂时保留我更为详细的方法,以便其他同事更容易看到发生了什么。我会及时转换它。
/// <summary>
/// Helper methods for the lists.
/// </summary>
public static class ListExtensions
{
    public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize) 
    {
        return source
            .Select((x, i) => new { Index = i, Value = x })
            .GroupBy(x => x.Index / chunkSize)
            .Select(x => x.Select(v => v.Value).ToList())
            .ToList();
    }
}