Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.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# 将列表拆分为大小为N的较小列表_C#_List_Split - Fatal编程技术网

C# 将列表拆分为大小为N的较小列表

C# 将列表拆分为大小为N的较小列表,c#,list,split,C#,List,Split,我正在尝试将一个列表拆分为一系列较小的列表 我的问题:我的列表拆分功能无法将列表拆分为正确大小的列表。它应该将它们拆分为大小为30的列表,而不是将它们拆分为大小为114的列表 如何使我的函数将列表拆分为X个大小小于等于30的列表 public static List<List<float[]>> splitList(List <float[]> locations, int nSize=30) { List<List<flo

我正在尝试将一个列表拆分为一系列较小的列表

我的问题:我的列表拆分功能无法将列表拆分为正确大小的列表。它应该将它们拆分为大小为30的列表,而不是将它们拆分为大小为114的列表

如何使我的函数将列表拆分为X个大小小于等于30的列表

public static List<List<float[]>> splitList(List <float[]> locations, int nSize=30) 
{       
    List<List<float[]>> list = new List<List<float[]>>();

    for (int i=(int)(Math.Ceiling((decimal)(locations.Count/nSize))); i>=0; i--) {
        List <float[]> subLocat = new List <float[]>(locations); 

        if (subLocat.Count >= ((i*nSize)+nSize))
            subLocat.RemoveRange(i*nSize, nSize);
        else subLocat.RemoveRange(i*nSize, subLocat.Count-(i*nSize));

        Debug.Log ("Index: "+i.ToString()+", Size: "+subLocat.Count.ToString());
        list.Add (subLocat);
    }

    return list;
}
公共静态列表拆分列表(列表位置,int nSize=30)
{       
列表=新列表();
对于(inti=(int)(数学上限((十进制)(locations.Count/nSize));i>=0;i--){
列表子位置=新列表(位置);
if(sublocate.Count>=((i*nSize)+nSize))
子位置移除范围(i*nSize,nSize);
else sublocate.RemoveRange(i*nSize,sublocate.Count-(i*nSize));
Log(“索引:“+i.ToString()+”,大小:“+sublocate.Count.ToString()”);
列表。添加(子定位);
}
退货清单;
}
如果我在大小为144的列表上使用该函数,则输出为:

索引:4,大小:120
索引:3,大小:114
索引:2,大小:114
索引:1,大小:114
索引:0,大小:114

公共静态列表拆分列表(列表位置,int nSize=30)
{        
var list=新列表();
对于(int i=0;i
通用版本:

public static IEnumerable<List<T>> SplitList<T>(List<T> locations, int nSize=30)  
{        
    for (int i = 0; i < locations.Count; i += nSize) 
    { 
        yield return locations.GetRange(i, Math.Min(nSize, locations.Count - i)); 
    }  
} 
公共静态IEnumerable拆分列表(列表位置,int nSize=30)
{        
对于(int i=0;i
那么:

while(locations.Any())
{    
    list.Add(locations.Take(nSize).ToList());
    locations= locations.Skip(nSize).ToList();
}

我有一个通用方法,可以采用包括float在内的任何类型,并且已经过单元测试,希望它有帮助:

    /// <summary>
    /// Breaks the list into groups with each group containing no more than the specified group size
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="values">The values.</param>
    /// <param name="groupSize">Size of the group.</param>
    /// <returns></returns>
    public static List<List<T>> SplitList<T>(IEnumerable<T> values, int groupSize, int? maxCount = null)
    {
        List<List<T>> result = new List<List<T>>();
        // Quick and special scenario
        if (values.Count() <= groupSize)
        {
            result.Add(values.ToList());
        }
        else
        {
            List<T> valueList = values.ToList();
            int startIndex = 0;
            int count = valueList.Count;
            int elementCount = 0;

            while (startIndex < count && (!maxCount.HasValue || (maxCount.HasValue && startIndex < maxCount)))
            {
                elementCount = (startIndex + groupSize > count) ? count - startIndex : groupSize;
                result.Add(valueList.GetRange(startIndex, elementCount));
                startIndex += elementCount;
            }
        }


        return result;
    }
//
///将列表分成多个组,每个组包含的组大小不超过指定的组大小
/// 
/// 
///价值观。
///组的大小。
/// 
公共静态列表拆分列表(IEnumerable值,int groupSize,int?maxCount=null)
{
列表结果=新列表();
//快速特殊场景
if(values.Count()Count)?Count-startIndex:groupSize;
Add(valueList.GetRange(startIndex,elementCount));
startIndex+=元素计数;
}
}
返回结果;
}

我建议使用此扩展方法按指定的块大小将源列表分块到子列表:

/// <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();
    }
}
//
///列表的帮助器方法。
/// 
公共静态类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();
}
}

例如,如果您将18个项目的列表按每个块5个项目进行分块,它将为您提供包含4个子列表的列表,其中包含以下项目:5-5-5-3。

Serj Tm解决方案很好,这也是作为列表扩展方法的通用版本(将其放入静态类中):

公共静态列表拆分(此列表项,int sliceSize=30)
{
列表=新列表();
for(int i=0;i
我认为公认答案(Serj Tm)最可靠,但我想推荐一个通用版本

public static List<List<T>> splitList<T>(List<T> locations, int nSize = 30)
{
    var list = new List<List<T>>();

    for (int i = 0; i < locations.Count; i += nSize)
    {
        list.Add(locations.GetRange(i, Math.Min(nSize, locations.Count - i)));
    }

    return list;
}
公共静态列表拆分列表(列表位置,int nSize=30)
{
var list=新列表();
对于(int i=0;i
库中有名为
批处理的方法

List<int> ids = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; // 10 elements
int counter = 1;
foreach(var batch in ids.Batch(2))
{
    foreach(var eachId in batch)
    {
        Console.WriteLine("Batch: {0}, Id: {1}", counter, eachId);
    }
    counter++;
}

id
被分成5个块,包含2个元素。

在mhand的非常有用的注释之后添加

While(source.Any())
{
     ...
}
public static IEnumerable<List<T>> BatchBy<T>(this IEnumerable<T> enumerable, int batchSize)
{
    using (var enumerator = enumerable.GetEnumerator())
    {
        List<T> list = null;
        while (enumerator.MoveNext())
        {
            if (list == null)
            {
                list = new List<T> {enumerator.Current};
            }
            else if (list.Count < batchSize)
            {
                list.Add(enumerator.Current);
            }
            else
            {
                yield return list;
                list = new List<T> {enumerator.Current};
            }
        }

        if (list?.Count > 0)
        {
            yield return list;
        }
    }
}
原始答案 虽然大多数解决方案可能有效,但我认为它们效率不高。假设您只需要前几个块的前几个项。这样,您就不想迭代序列中的所有(无数)项了

以下内容最多会列举两次:一次用于获取,一次用于跳过。它不会枚举比您使用的元素更多的元素:

public static IEnumerable<IEnumerable<TSource>> ChunkBy<TSource>
    (this IEnumerable<TSource> source, int chunkSize)
{
    while (source.Any())                     // while there are elements left
    {   // still something to chunk:
        yield return source.Take(chunkSize); // return a chunk of chunkSize
        source = source.Skip(chunkSize);     // skip the returned chunk
    }
}
Any将获取枚举数do 1 MoveNext(),并在处理枚举数后返回返回值。此操作将执行N次

yield return source.Take(chunkSize);
根据计划,这将执行以下操作:

public static IEnumerable<TSource> Take<TSource>(this IEnumerable<TSource> source, int count)
{
    return TakeIterator<TSource>(source, count);
}

static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> source, int count)
{
    foreach (TSource element in source)
    {
        yield return element;
        if (--count == 0) break;
    }
}
再次:我们将查看以查找
skipiterator

static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count)
{
    using (IEnumerator<TSource> e = source.GetEnumerator()) 
    {
        while (count > 0 && e.MoveNext()) count--;
        if (count <= 0) 
        {
            while (e.MoveNext()) yield return e.Current;
        }
    }
}
因此,如果您决定枚举所有块的所有元素:

MoveNext: numberOfChunks + all elements + all elements = about twice the sequence
Current: every item is accessed exactly once
MoveNext是否需要大量工作取决于源序列的类型。对于列表和数组,这是一个简单的索引增量,可能还有一个超出范围的检查

但是,如果IEnumerable是数据库查询的结果,请确保数据确实在计算机上实现,否则数据将被多次提取。DbContext和Dapper将在访问数据之前将数据正确地传输到本地进程。如果多次枚举同一序列,则不会多次获取该序列。Dapper返回一个对象,它是一个列表,DbContext会记住数据已经被提取


这取决于您的存储库,在您开始将项目划分为块之前调用AsEnumerable()或ToLists()是否明智

尽管上面的许多答案都可以完成这项工作,但它们都会在一个永无止境的序列(或非常长的序列)上失败。下面是一个完全在线的实现,它保证了最佳的时间和内存复杂性。我们只迭代源可枚举项一次,并使用收益率返回进行延迟计算。消费者可以在每次迭代时丢弃列表,使内存占用量相等
source = source.Skip(chunkSize);
static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count)
{
    using (IEnumerator<TSource> e = source.GetEnumerator()) 
    {
        while (count > 0 && e.MoveNext()) count--;
        if (count <= 0) 
        {
            while (e.MoveNext()) yield return e.Current;
        }
    }
}
MoveNext calls: N + N*M + N*chunkSize
Current calls: N*M; (only the items you really access)
MoveNext: numberOfChunks + all elements + all elements = about twice the sequence
Current: every item is accessed exactly once
public static IEnumerable<List<T>> BatchBy<T>(this IEnumerable<T> enumerable, int batchSize)
{
    using (var enumerator = enumerable.GetEnumerator())
    {
        List<T> list = null;
        while (enumerator.MoveNext())
        {
            if (list == null)
            {
                list = new List<T> {enumerator.Current};
            }
            else if (list.Count < batchSize)
            {
                list.Add(enumerator.Current);
            }
            else
            {
                yield return list;
                list = new List<T> {enumerator.Current};
            }
        }

        if (list?.Count > 0)
        {
            yield return list;
        }
    }
}
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> items, int maxItems)
{
    return items.Select((item, index) => new { item, index })
                .GroupBy(x => x.index / maxItems)
                .Select(g => g.Select(x => x.item));
}
private IEnumerable<IList<T>> SplitList<T>(IList<T> list, int totalChunks)
{
    IList<T> auxList = new List<T>();
    int totalItems = list.Count();

    if (totalChunks <= 0)
    {
        yield return auxList;
    }
    else 
    {
        for (int i = 0; i < totalItems; i++)
        {               
            auxList.Add(list[i]);           

            if ((i + 1) % totalChunks == 0)
            {
                yield return auxList;
                auxList = new List<T>();                
            }

            else if (i == totalItems - 1)
            {
                yield return auxList;
            }
        }
    }   
}
public static IList<IList<T>> SplitList<T>(this IList<T> list, int chunkSize)
{
    var chunks = new List<IList<T>>();
    List<T> chunk = null;
    for (var i = 0; i < list.Count; i++)
    {
        if (i % chunkSize == 0)
        {
            chunk = new List<T>(chunkSize);
            chunks.Add(chunk);
        }
        chunk.Add(list[i]);
    }
    return chunks;
}
public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize)
    {           
        var result = new List<List<T>>();
        for (int i = 0; i < source.Count; i += chunkSize)
        {
            var rows = new List<T>();
            for (int j = i; j < i + chunkSize; j++)
            {
                if (j >= source.Count) break;
                rows.Add(source[j]);
            }
            result.Add(rows);
        }
        return result;
    }
List<int> orginalList =new List<int>(){1,2,3,4,5,6,7,8,9,10,12};
Dictionary<int,List<int>> dic = new Dictionary <int,List<int>> ();
int batchcount = orginalList.Count/2; //To List into two 2 parts if you 
 want three give three
List<int> lst = new List<int>();
for (int i=0;i<orginalList.Count; i++)
{
lst.Add(orginalList[i]);
if (i % batchCount == 0 && i!=0)
{
Dic.Add(threadId, lst);
lst = new List<int>();**strong text**
threadId++;
}
}
if(lst.Count>0)
Dic.Add(threadId, lst); //in case if any dayleft 
foreach(int BatchId in Dic.Keys)
{
  Console.Writeline("BatchId:"+BatchId);
  Console.Writeline('Batch Count:"+Dic[BatchId].Count);
}
        var categories = Properties.Settings.Default.MovementStatsCategories;
        var items = summariesWithinYear
            .Select(s =>  s.sku).Distinct().ToList();

        //need to run by chunks of 10,000
        var count = items.Count;
        var counter = 0;
        var numToTake = 10000;

        while (count > 0)
        {
            var itemsChunk = items.Skip(numToTake * counter).Take(numToTake).ToList();
            counter += 1;

            MovementHistoryUtilities.RecordMovementHistoryStatsBulk(itemsChunk, categories, nLogger);

            count -= numToTake;
        }
public static IEnumerable<IEnumerable<TSource>> ChunkBy<TSource>(this IEnumerable<TSource> source, int chunkSize)
{
    if (source is null)
    {
        throw new ArgumentNullException(nameof(source));
    }
    if (chunkSize <= 0)
    {
        throw new ArgumentOutOfRangeException(nameof(chunkSize), chunkSize, "The argument must be greater than zero.");
    }

    return source
        .Select((x, i) => new ChunkedValue<TSource>(x, i / chunkSize))
        .GroupBy(cv => cv.ChunkIndex)
        .Select(g => g.Select(cv => cv.Value));
} 

[StructLayout(LayoutKind.Auto)]
[DebuggerDisplay("{" + nameof(ChunkedValue<T>.ChunkIndex) + "}: {" + nameof(ChunkedValue<T>.Value) + "}")]
private struct ChunkedValue<T>
{
    public ChunkedValue(T value, int chunkIndex)
    {
        this.ChunkIndex = chunkIndex;
        this.Value = value;
    }

    public int ChunkIndex { get; }

    public T Value { get; }
}
int chunkSize = 30;
foreach (var chunk in collection.ChunkBy(chunkSize))
{
    foreach (var item in chunk)
    {
        // your code for item here.
    }
}
int chunkSize = 30;
var chunkList = new List<List<T>>();
foreach (var chunk in collection.ChunkBy(chunkSize))
{
    // create a list with the correct capacity to be able to contain one chunk
    // to avoid the resizing (additional memory allocation and memory copy) within the List<T>.
    var list = new List<T>(chunkSize);
    list.AddRange(chunk);
    chunkList.Add(list);
}
    public static IEnumerable<IEnumerable<T>> Split<T>(IEnumerable<T> source, int size = 30)
    {
        var count = source.Count();
        for (int i = 0; i < count; i += size)
        {
            yield return source
                .Skip(Math.Min(size, count - i))
                .Take(size);
        }
    }