使用 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 函数可以帮助我完成此任务?
我在想GroupBy
或SelectMany
我不知道他们是否会帮助我,但他们可能会
任何帮助将不胜感激 =) :**
【问题讨论】:
在纯 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 拆分数组的主要内容,如果未能解决你的问题,请参考以下文章
Python使用numpy函数vsplit垂直(行角度)拆分numpy数组(返回拆分后的numpy数组列表)实战:垂直拆分二维numpy数组split函数垂直拆分二维numpy数组
Python使用numpy函数hsplit水平(按列)拆分numpy数组(返回拆分后的numpy数组列表)实战:水平(按列)拆分二维numpy数组split函数水平(按列)拆分二维numpy数组