C# 在x个较小的列表之间平均拆分项目列表
我再次问这个问题,自从上次我问它以来,它被错误地标记为重复。这次我将提供更多的信息,这可能会使我更容易理解我的需求(这很可能是我自己没有正确定义问题的过错) 我正在尝试将一个泛型类型的列表拆分为4个列表。为了简单易懂,我将在本例中使用整数列表,但这不会有什么区别 我做了很多搜索,找到了很多答案,比如,我尝试了MoreLinq的批处理方法等等。这些建议很好地完成了它们应该做的事情,但它们没有按照我需要的方式工作 如果我有一个包含以下元素的列表(整数范围为1-25): 然后我需要做的是创建4个列表,其中包含可变数量的元素,其中元素在同一个列表中递增,而不是使用下一个元素跳转到下一个列表C# 在x个较小的列表之间平均拆分项目列表,c#,linq,list,C#,Linq,List,我再次问这个问题,自从上次我问它以来,它被错误地标记为重复。这次我将提供更多的信息,这可能会使我更容易理解我的需求(这很可能是我自己没有正确定义问题的过错) 我正在尝试将一个泛型类型的列表拆分为4个列表。为了简单易懂,我将在本例中使用整数列表,但这不会有什么区别 我做了很多搜索,找到了很多答案,比如,我尝试了MoreLinq的批处理方法等等。这些建议很好地完成了它们应该做的事情,但它们没有按照我需要的方式工作 如果我有一个包含以下元素的列表(整数范围为1-25): 然后我需要做的是创建4个列表,
[ 1, 2, 3, 4, 5, 6, 7]
[ 8, 9, 10, 11, 12, 13, 14]
[15, 16, 17, 18, 19, 20, 21]
[20, 21, 22, 23, 24, 25]
当使用任何一个链接问题的答案时,以4个“部分”作为参数,我得到如下列表(这是一个示例,其中元素跳转到下一个列表,而不仅仅是列表中的下一个元素):
或者这个(与MoreLinq的批处理方法相同)
因此,第一个解决方案将列表拆分为4个列表,但将元素按错误的顺序排列。第二种解决方案按正确的顺序拆分列表,但长度不正确。在上一个解决方案中,他得到了X个列表,每个列表中有4个元素,其中我需要有4个列表,每个列表中有X个元素 您可以使用以下扩展方法按所需数量的子列表拆分列表,并在第一个子列表中包含其他项目:
public static IEnumerable<List<T>> Split<T>(this List<T> source, int count)
{
int rangeSize = source.Count / count;
int firstRangeSize = rangeSize + source.Count % count;
int index = 0;
yield return source.GetRange(index, firstRangeSize);
index += firstRangeSize;
while (index < source.Count)
{
yield return source.GetRange(index, rangeSize);
index += rangeSize;
}
}
结果是
[
[ 1, 2, 3, 4, 5, 6, 7 ],
[ 8, 9, 10, 11, 12, 13 ],
[ 14, 15, 16, 17, 18, 19 ],
[ 20, 21, 22, 23, 24, 25 ]
]
更新:此解决方案向每个范围添加其他项
public static IEnumerable<List<T>> Split<T>(this List<T> source, int count)
{
int rangeSize = source.Count / count;
int additionalItems = source.Count % count;
int index = 0;
while (index < source.Count)
{
int currentRangeSize = rangeSize + ((additionalItems > 0) ? 1 : 0);
yield return source.GetRange(index, currentRangeSize);
index += currentRangeSize;
additionalItems--;
}
}
公共静态IEnumerable拆分(此列表源,整数计数)
{
int rangeSize=源。计数/计数;
int additionalItems=source.Count%Count;
int指数=0;
while(索引0)?1:0);
收益返回源.GetRange(索引,currentRangeSize);
索引+=当前范围大小;
其他项目--;
}
}
您可以使用以下扩展方法在所需数量的子列表上拆分列表,并在第一个子列表中包含其他项目:
public static IEnumerable<List<T>> Split<T>(this List<T> source, int count)
{
int rangeSize = source.Count / count;
int firstRangeSize = rangeSize + source.Count % count;
int index = 0;
yield return source.GetRange(index, firstRangeSize);
index += firstRangeSize;
while (index < source.Count)
{
yield return source.GetRange(index, rangeSize);
index += rangeSize;
}
}
结果是
[
[ 1, 2, 3, 4, 5, 6, 7 ],
[ 8, 9, 10, 11, 12, 13 ],
[ 14, 15, 16, 17, 18, 19 ],
[ 20, 21, 22, 23, 24, 25 ]
]
更新:此解决方案向每个范围添加其他项
public static IEnumerable<List<T>> Split<T>(this List<T> source, int count)
{
int rangeSize = source.Count / count;
int additionalItems = source.Count % count;
int index = 0;
while (index < source.Count)
{
int currentRangeSize = rangeSize + ((additionalItems > 0) ? 1 : 0);
yield return source.GetRange(index, currentRangeSize);
index += currentRangeSize;
additionalItems--;
}
}
公共静态IEnumerable拆分(此列表源,整数计数)
{
int rangeSize=源。计数/计数;
int additionalItems=source.Count%Count;
int指数=0;
while(索引0)?1:0);
收益返回源.GetRange(索引,currentRangeSize);
索引+=当前范围大小;
其他项目--;
}
}
它首先引入了一个计数器(currentGroupIndex
),该计数器从零开始,将为列表中的每个元素递增。当组大小达到时,索引将重置为零。变量
step1
现在包含包含组
和值
属性的项。然后在
GroupBy
语句中使用Group
值
它首先引入了一个计数器(currentGroupIndex
),该计数器从零开始,将为列表中的每个元素递增。当组大小达到时,索引将重置为零。变量
step1
现在包含包含组
和值
属性的项。然后在
GroupBy
语句中使用Group
值。这里是另一个基于IEnumerable
的解决方案。它具有以下特点:
- 始终生成
项,如果源可枚举项小于批大小,则将生成空列表batchCount
- 偏爱前面较大的列表(例如,当batchCount为2且大小为3时,结果的长度将为[2,1]
- 多次迭代IEnumerable。这意味着,若在此处执行实体框架查询之类的操作,则应在某处调用AsEnumerable
List
公共静态类批处理操作
{
公共静态IEnumerable批处理(此列表项,int batchCount)
{
int totalSize=items.Count;
int剩余=总大小%batchCount;
int skip=0;
对于(int i=0;i int size=totalSize/batchCount+(i这里是另一个基于IEnumerable
的解决方案。它具有以下特点:
- 始终生成
batchCount
项,如果源可枚举项小于批大小,则将生成空列表
- 偏爱前面较大的列表(例如,当batchCount为2且大小为3时,结果的长度将为[2,1]
- 多次迭代IEnumerable。这意味着,若在此处执行实体框架查询之类的操作,则应在某处调用AsEnumerable
第一个示例针对List
公共静态类批处理操作
{
公共静态IEnumerable批处理(此列表项,int batchCount)
{
int totalSize=items.Count;
整数=总
public static IEnumerable<List<T>> Split<T>(this List<T> source, int count)
{
int rangeSize = source.Count / count;
int additionalItems = source.Count % count;
int index = 0;
while (index < source.Count)
{
int currentRangeSize = rangeSize + ((additionalItems > 0) ? 1 : 0);
yield return source.GetRange(index, currentRangeSize);
index += currentRangeSize;
additionalItems--;
}
}
const int groupSize = 4;
var items = new []{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25};
var currentGroupIndex=-1;
var step1 = items.Select(a =>{
if (++currentGroupIndex >= groupSize)
currentGroupIndex = 0;
return new {Group = currentGroupIndex, Value = a};
}).ToArray();
var step2 = step1.GroupBy(a => a.Group).Select(a => a.ToArray()).ToArray();
var group1 = step2[0].Select(a => a.Value).ToArray();
var group2 = step2[1].Select(a => a.Value).ToArray();
var group3 = step2[2].Select(a => a.Value).ToArray();
var group4 = step2[3].Select(a => a.Value).ToArray();
public static class BatchOperations
{
public static IEnumerable<List<T>> Batch<T>(this List<T> items, int batchCount)
{
int totalSize = items.Count;
int remain = totalSize % batchCount;
int skip = 0;
for (int i = 0; i < batchCount; i++)
{
int size = totalSize / batchCount + (i <= remain ? 1 : 0);
if (skip + size > items.Count) yield return new List<T>(0);
else yield return items.GetRange(skip, size);
skip += size;
}
}
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> items, int batchCount)
{
int totalSize = items.Count();
int remain = totalSize%batchCount;
int skip = 0;
for (int i = 0; i < batchCount; i++)
{
int size = totalSize/batchCount + (i <= remain ? 1 : 0);
yield return items.Skip(skip).Take(size);
skip += size;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
public static class EnumerableExt
{
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> input, int blockCount, int count)
{
int blockSize = count/blockCount;
int currentBlockSize = blockSize + count%blockSize;
var enumerator = input.GetEnumerator();
while (enumerator.MoveNext())
{
yield return nextPartition(enumerator, currentBlockSize);
currentBlockSize = blockSize;
}
}
private static IEnumerable<T> nextPartition<T>(IEnumerator<T> enumerator, int blockSize)
{
do
{
yield return enumerator.Current;
}
while (--blockSize > 0 && enumerator.MoveNext());
}
}
class Program
{
private void run()
{
var list = Enumerable.Range(1, 25).ToList();
var sublists = list.Partition(4, list.Count);
foreach (var sublist in sublists)
Console.WriteLine(string.Join(" ", sublist.Select(element => element.ToString())));
}
static void Main()
{
new Program().run();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Splitter
{
class Program
{
static void Main(string[] args)
{
List<int> numbers = Enumerable.Range(1, 25).ToList();
int groupCount = 4;
var lists = numbers.Groupem(groupCount, (e, i) =>
{
// In what group do i wanna have this element.
int divider = numbers.Count / groupCount;
int overflow = numbers.Count % divider;
int index = (i - overflow) / divider;
return index < 0 ? 0 : index;
});
Console.WriteLine("numbers: {0}", numbers.ShowContent());
Console.WriteLine("Parts");
foreach (IEnumerable<int> list in lists)
{
Console.WriteLine("{0}", list.ShowContent());
}
}
}
public static class EnumerableExtensions
{
private static List<T>[] CreateGroups<T>(int size)
{
List<T>[] groups = new List<T>[size];
for (int i = 0; i < groups.Length; i++)
{
groups[i] = new List<T>();
}
return groups;
}
public static void Each<T>(this IEnumerable<T> source, Action<T, int> action)
{
var i = 0;
foreach (var e in source) action(e, i++);
}
public static IEnumerable<IEnumerable<T>> Groupem<T>(this IEnumerable<T> source, int groupCount, Func<T, int, int> groupPicker, bool failOnOutOfBounds = true)
{
if (groupCount <= 0) throw new ArgumentOutOfRangeException("groupCount", "groupCount must be a integer greater than zero.");
List<T>[] groups = CreateGroups<T>(groupCount);
source.Each((element, index) =>
{
int groupIndex = groupPicker(element, index);
if (groupIndex < 0 || groupIndex >= groups.Length)
{
// When allowing some elements to fall out, set failOnOutOfBounds to false
if (failOnOutOfBounds)
{
throw new Exception("Some better exception than this");
}
}
else
{
groups[groupIndex].Add(element);
}
});
return groups;
}
public static string ShowContent<T>(this IEnumerable<T> list)
{
return "[" + string.Join(", ", list) + "]";
}
}
}
public static IList<Ilist<T>> Segment<T>(
this IEnumerable<T> source,
int segments)
{
if (segments < 1)
{
throw new ArgumentOutOfRangeException("segments");
}
var list = source.ToList();
var result = new IList<T>[segments];
// In case the source is empty.
if (!list.Any())
{
for (var i = 0; i < segments; i++)
{
result[i] = new T[0];
}
return result;
}
int remainder;
var segmentSize = Math.DivRem(list.Count, segments, out remainder);
var postion = 0;
var segment = 0;
while (segment < segments)
{
var count = segmentSize;
if (remainder > 0)
{
remainder--;
count++;
}
result[segment] = list.GetRange(position, count);
segment++;
position += count;
}
return result;
}