给定一个sorted list
和一个变量n
,我想将list
分解为n
部件。对于n = 3,
,我期望有三个lists
,而最后一个则是overflow
。
我想:0,1,2,3,4,5
,6,7,8,9,10,11
,12,13,14,15,16,17
如果items
在list
中的数量不是n
的divisible
,那么只需将溢出(mod n)
放在最后一个list
中即可。
这不管用:
static class Program
{
static void Main(string[] args)
{
var input = new List<double>();
for (int k = 0; k < 18; ++k)
{
input.Add(k);
}
var result = input.Split(3);
foreach (var resul in result)
{
foreach (var res in resul)
{
Console.WriteLine(res);
}
}
}
}
static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
{
int i = 0;
var splits = from item in list
group item by i++ % parts into part
select part.AsEnumerable();
return splits;
}
}
发布于 2022-11-28 00:17:43
我认为您将受益于Linq的.Chunk()方法。
如果您首先计算出包含相等项计数的部分的数量,则可以在对list
的其余部分进行yield return
之前,在list
的其余部分(如果list
不能被n
整除)之前,对每个块进行块划分。
正如神秘性所指出的,应该将list
具体化为一个ICollection<T>
,以避免可能的多个枚举。物化可以通过尝试将list
转换为ICollection<T>
来获得,如果不成功,则返回到调用list.ToList()
。
因此,扩展方法的一个可能实现是:
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
{
var collection = list is ICollection<T> c
? c
: list.ToList();
var itemCount = collection.Count;
// return all items if source list is too short to split up
if (itemCount < parts)
{
yield return collection;
yield break;
}
var itemsInEachChunk = itemCount / parts;
var chunks = itemCount % parts == 0
? parts
: parts - 1;
var itemsToChunk = chunks * itemsInEachChunk;
foreach (var chunk in collection.Take(itemsToChunk).Chunk(itemsInEachChunk))
{
yield return chunk;
}
if (itemsToChunk < itemCount)
{
yield return collection.Skip(itemsToChunk);
}
}
例如小提琴这里。
发布于 2022-11-27 23:17:44
我发现你的代码有两个问题。首先,输出结果的方式是不可能告诉值的分组的,因为您只是在它自己的行上输出每个值。
这可以通过对组中的每个值使用Console.Write
来解决,然后在组完成时添加一个Console.WriteLine()
。这样,来自每个组的值将显示在单独的行上。我们还可能希望填充这些值,以便通过获取最大值的长度并将其传递给PadRight
方法,使它们很好地对齐:
static void Main(string[] args)
{
var numItems = 18;
var splitBy = 3;
var input = Enumerable.Range(0, numItems).ToList();
var results = input.Split(splitBy);
// Get the length of the largest value to use for padding smaller values,
// so all the columns will line up when we display the results
var padValue = input.Max().ToString().Length + 1;
foreach (var group in results)
{
foreach (var item in group)
{
Console.Write($"{item}".PadRight(padValue));
}
Console.WriteLine();
}
Console.Write("\n\nDone. Press any key to exit...");
Console.ReadKey();
}
现在,您的结果看起来相当不错,但我们可以看到,这些数字并没有像我们预期的那样分组:
0 3 6 9 12 15
1 4 7 10 13 16
2 5 8 11 14 17
原因是我们将每个项目的其余部分除以部分数进行分组。因此,第一组包含被3
除以后余数为0
的所有数字,第二组包含余数为1
等的所有项。
为了解决这个问题,我们应该将项目的索引除以一行中的项目数(列数)。
换句话说,18
项除以3
行将导致每行6
项。用整数除法,0
到5
的所有索引除以6
时都有0
的余数,从6
到11
的所有索引除以6
时都有一个1
的余数,从12
到17
的所有索引除以2
时都有6
的余数。
但是,我们也必须能够处理溢出数字。这样做的一种方法是检查索引是否大于或等于rows * columns
(也就是说,它最终将位于新行而不是最后一行)。如果这是真的,那么我们将其设置为最后一行。
我在linq方面不是很好,所以可能有更好的方法来编写它,但是我们可以这样修改我们的扩展方法:
public static IEnumerable<IEnumerable<T>> Split<T>(
this IEnumerable<T> list, int parts)
{
int numItems = list.Count();
int columns = numItems / parts;
int overflow = numItems % parts;
int index = 0;
return from item in list
group item by
index++ >= (parts * columns) ? parts - 1 : (index - 1) / columns
into part
select part.AsEnumerable();
}
现在我们的结果看起来更好了:
// For 18 items split into 3
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
// For 25 items split into 7
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14
15 16 17
18 19 20 21 22 23 24
发布于 2022-11-28 04:09:54
这应该能行。
因此,每个列表(理想情况下)都应该有x/n元素,其中x=>编号。列表中的元素& n=>编号。它必须分成几个部分
如果x不能被n整除,那么每个列表都应该有x/n (四舍五入到最近的整数)。那就算了吧。做“你”。而最后一个列表应该有x*(n-1)。那就算了吧。是“z”。
第一个for-循环所做的是重复使用适当的no创建列表的过程。元素数n次。
if-else块用于查看创建的列表是否是最后一个。如果是最后一个,它有z项。如果没有,它有Y个项目。
嵌套的for-循环将列表项添加到“子列表”(列表)中,然后将其添加到要返回的主列表(列表)中。
此解决方案(明显地)不同于您的签名和其他解决方案。我使用这种方法是因为代码(可以说)更容易理解,尽管更长。当我过去寻找解决方案的时候,我经常应用解决方案,在那里我能准确地理解正在发生的事情。我无法完全理解这个问题的其他解决方案(尚未掌握适当的编程诀窍),所以我介绍了我在下面编写的解决方案,以防您最终陷入同样的困境。
如果我需要做任何改变,请告诉我。
static class Program
{
static void Main(string[] args)
{
var input = new List<String>();
for (int k = 0; k < 18; ++k)
{
input.Add(k.ToString());
}
var result = SplitList(input, 5);//I've used 5 but it can be any number
foreach (var resul in result)
{
foreach (var res in result)
{
Console.WriteLine(res);
}
}
}
public static List<List<string>> SplitList (List<string> origList, int n)
{//"n" is the number of parts you want to split your list into
int splitLength = origList.Count / n; //splitLength is no. of items in each list bar the last one. (In case of overflow)
List<List<string>> listCollection = new List<List<string>>();
for ( int i = 0; i < n; i++ )
{
List<string> tempStrList = new List<string>();
if ( i < n - 1 )
{
for ( int j = i * splitLength; j < (i + 1) * splitLength; j++ )
{
tempStrList.Add(origList[j]);
}
}
else
{
for ( int j = i * splitLength; j < origList.Count; j++ )
{
tempStrList.Add(origList[j]);
}
}
listCollection.Add(tempStrList);
}
return listCollection;
}
}
https://stackoverflow.com/questions/74595570
复制相似问题