使用 LINQ 拆分数组

Posted

技术标签:

【中文标题】使用 LINQ 拆分数组【英文标题】:Splitting an array using LINQ 【发布时间】:2012-05-31 03:15:11 【问题描述】:

我有一个这样的单维集合:

[1,2,4,5.....n]

我想将该集合转换为这样的二维集合:

[[1,2,3],
[4,5,6],
...]

如果你愿意,基本上我想对数组进行分组或拆分,以“n”个成员为一组

我可以使用foreach 语句来做到这一点,但我目前正在学习 LINQ,因此我不想遍历所有元素并手动创建一个新数组,而是想使用 LINQ 功能(如果适用)

是否有任何 LINQ 函数可以帮助我完成此任务?

我在想GroupBySelectMany 我不知道他们是否会帮助我,但他们可能会

任何帮助将不胜感激 =) :**

【问题讨论】:

在纯 LINQ 中以多种不同方式编写这样的查询是可能的,但我不建议这样做,这会非常低效。 【参考方案1】:

您可以按索引除以批量大小进行分组,如下所示:

var batchSize = 3;
var batched = orig
    .Select((Value, Index) => new Value, Index)
    .GroupBy(p => p.Index/batchSize)
    .Select(g => g.Select(p => p.Value).ToList());

【讨论】:

这正是我所寻找的——真的很聪明。 我在考虑如何使用 GroupBy 来做到这一点,但不知道如何考虑索引...谢谢。【参考方案2】:

使用MoreLinq.Batch

 var result = inputArray.Batch(n); // n -> batch size

例子

    var inputs = Enumerable.Range(1,10);

    var output = inputs.Batch(3);


    var outputAsArray = inputs.Batch(3).Select(x=>x.ToArray()).ToArray(); //If require as array

【讨论】:

+1 获取 MoreLinq 的链接,谢谢!我只想注意,在某些情况下,我们必须将 MoreLinq 作为源代码而不是编译的 dll 嵌入,例如如果我们使用 LinqBridge。 这很有趣,但我检查了源代码,它是用foreach完成的 大多数方法都使用 foreach 并谨慎使用 yield 关键字。对于任何此类要求,我首先尝试在MoreLinq、LinqExtensions 等中找出现有的扩展。如果我没有找到,并且有意义,我会创建自己的扩展。【参考方案3】:

你想要Take()Skip()。这些方法可以让您拆分IEnumerable。然后你就可以用Concat()把它们再拍在一起了。

【讨论】:

【参考方案4】:

下面的示例将一个数组分成一组,每组 4 项。

int[] items = Enumerable.Range(1, 20).ToArray(); // Generate a test array to split
int[][] groupedItems = items
                         .Select((item, index) => index % 4 == 0 ? items.Skip(index).Take(4).ToArray() : null)
                         .Where(group => group != null)
                         .ToArray();

【讨论】:

【参考方案5】:

它不是纯粹的 LINQ,但它打算与它一起使用:

public static class MyEnumerableExtensions

    public static IEnumerable<T[]> Split<T>(this IEnumerable<T> source, int size)
    
        if (source == null)
        
            throw new ArgumentNullException("source can't be null.");
        

        if (size == 0)
        
            throw new ArgumentOutOfRangeException("Chunk size can't be 0.");
        

        List<T> result = new List<T>(size);
        foreach (T x in source)
        
            result.Add(x);
            if (result.Count == size)
            
                yield return result.ToArray();
                result = new List<T>(size);
            
        
    

它可以在您的代码中用作:

private void Test()

    // Here's your original sequence
    IEnumerable<int> seq = new[]  1, 2, 3, 4, 5, 6 ;

    // Here's the result of splitting into chunks of some length 
    // (here's the chunks length equals 3). 
    // You can manipulate with this sequence further, 
    // like filtering or joining e.t.c.
    var splitted = seq.Split(3);

【讨论】:

一个语义点:英文中的“splice”实际上是“join together”的意思,而方法实际上是把数组拉开。 在最后一步如果result.Count @gabba 是的,谢谢!我假设初始序列将由k*size 元素组成。我认为如果不是这样,最好抛出异常。 @DmitryLobanov,如有疑问,请使用“cleave”——这意味着“分裂”和“融合在一起!”俗话说,“英语不借用其他语言。英语跟随其他语言走在黑暗的小巷里,把它们撞倒,在他们的口袋里翻找松散的语法。”【参考方案6】:

很简单:

static class LinqExtensions

    public static IEnumerable<IEnumerable<T>> ToPages<T>(this IEnumerable<T> elements, int pageSize)
    
        if (elements == null)
            throw new ArgumentNullException("elements");
        if (pageSize <= 0)
            throw new ArgumentOutOfRangeException("pageSize","Must be greater than 0!");

        int i = 0;
        var paged = elements.GroupBy(p => i++ / pageSize);
        return paged;
    

【讨论】:

【参考方案7】:

我基于 Jeremy Holovacs's 答案的解决方案并使用 Take() 和 Skip() 创建子数组。

        const int batchSize = 3;
        int[] array = new int[]  1,2,4,5.....n;

        var subArrays = from index in Enumerable.Range(0, array.Length / batchSize + 1)
                      select array.Skip(index * batchSize).Take(batchSize);

【讨论】:

以上是关于使用 LINQ 拆分数组的主要内容,如果未能解决你的问题,请参考以下文章

如何在多维数组上使用 LINQ 来“展开”数组?

C#字符串数组替换最后一个元素

使用 Linq 创建数组数组

Python使用numpy函数vsplit垂直(行角度)拆分numpy数组(返回拆分后的numpy数组列表)实战:垂直拆分二维numpy数组split函数垂直拆分二维numpy数组

Python使用numpy函数hsplit水平(按列)拆分numpy数组(返回拆分后的numpy数组列表)实战:水平(按列)拆分二维numpy数组split函数水平(按列)拆分二维numpy数组

使用 LINQ (C#) 对 n 维数组进行数组操作