首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >将列表分成n个等份

将列表分成n个等份
EN

Stack Overflow用户
提问于 2022-11-28 03:04:02
回答 3查看 101关注 0票数 -1

给定一个sorted list和一个变量n,我想将list分解为n部件。对于n = 3,,我期望有三个lists,而最后一个则是overflow

我想:0,1,2,3,4,56,7,8,9,10,1112,13,14,15,16,17

如果itemslist中的数量不是ndivisible,那么只需将溢出(mod n)放在最后一个list中即可。

这不管用:

代码语言:javascript
代码运行次数:0
运行
复制
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;
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-11-28 08:17:43

我认为您将受益于Linq的.Chunk()方法。

如果您首先计算出包含相等项计数的部分的数量,则可以在对list的其余部分进行yield return之前,在list的其余部分(如果list不能被n整除)之前,对每个块进行块划分。

正如神秘性所指出的,应该将list具体化为一个ICollection<T>,以避免可能的多个枚举。物化可以通过尝试将list转换为ICollection<T>来获得,如果不成功,则返回到调用list.ToList()

因此,扩展方法的一个可能实现是:

代码语言:javascript
代码运行次数:0
运行
复制
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);
    }
}

例如小提琴这里

票数 2
EN

Stack Overflow用户

发布于 2022-11-28 07:17:44

我发现你的代码有两个问题。首先,输出结果的方式是不可能告诉值的分组的,因为您只是在它自己的行上输出每个值。

这可以通过对组中的每个值使用Console.Write来解决,然后在组完成时添加一个Console.WriteLine()。这样,来自每个组的值将显示在单独的行上。我们还可能希望填充这些值,以便通过获取最大值的长度并将其传递给PadRight方法,使它们很好地对齐:

代码语言:javascript
代码运行次数:0
运行
复制
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();
} 

现在,您的结果看起来相当不错,但我们可以看到,这些数字并没有像我们预期的那样分组:

代码语言:javascript
代码运行次数:0
运行
复制
0  3  6  9  12 15
1  4  7  10 13 16
2  5  8  11 14 17

原因是我们将每个项目的其余部分除以部分数进行分组。因此,第一组包含被3除以后余数为0的所有数字,第二组包含余数为1等的所有项。

为了解决这个问题,我们应该将项目的索引除以一行中的项目数(列数)。

换句话说,18项除以3行将导致每行6项。用整数除法,05的所有索引除以6时都有0的余数,从611的所有索引除以6时都有一个1的余数,从1217的所有索引除以2时都有6的余数。

但是,我们也必须能够处理溢出数字。这样做的一种方法是检查索引是否大于或等于rows * columns (也就是说,它最终将位于新行而不是最后一行)。如果这是真的,那么我们将其设置为最后一行。

我在linq方面不是很好,所以可能有更好的方法来编写它,但是我们可以这样修改我们的扩展方法:

代码语言:javascript
代码运行次数:0
运行
复制
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();
}

现在我们的结果看起来更好了:

代码语言:javascript
代码运行次数:0
运行
复制
// 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
票数 1
EN

Stack Overflow用户

发布于 2022-11-28 12:09:54

这应该能行。

因此,每个列表(理想情况下)都应该有x/n元素,其中x=>编号。列表中的元素& n=>编号。它必须分成几个部分

如果x不能被n整除,那么每个列表都应该有x/n (四舍五入到最近的整数)。那就算了吧。做“你”。而最后一个列表应该有x*(n-1)。那就算了吧。是“z”。

第一个for-循环所做的是重复使用适当的no创建列表的过程。元素数n次。

if-else块用于查看创建的列表是否是最后一个。如果是最后一个,它有z项。如果没有,它有Y个项目。

嵌套的for-循环将列表项添加到“子列表”(列表)中,然后将其添加到要返回的主列表(列表)中。

此解决方案(明显地)不同于您的签名和其他解决方案。我使用这种方法是因为代码(可以说)更容易理解,尽管更长。当我过去寻找解决方案的时候,我经常应用解决方案,在那里我能准确地理解正在发生的事情。我无法完全理解这个问题的其他解决方案(尚未掌握适当的编程诀窍),所以我介绍了我在下面编写的解决方案,以防您最终陷入同样的困境。

如果我需要做任何改变,请告诉我。

代码语言:javascript
代码运行次数:0
运行
复制
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;
        }
    }
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74595570

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档