C# 拆分数组的最佳方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11207526/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to split an array
提问by thatuxguy
Afternoon, I need to find out what the best way to split an array into smaller "chunks" would be.
下午,我需要找出将数组拆分为更小的“块”的最佳方法是什么。
I am passing over about 1200 items, and need to split these into easier to handle groups of 100, then i need to pass them over to processed.
我传递了大约 1200 个项目,需要将它们分成更容易处理的 100 个组,然后我需要将它们传递给处理。
Could any one please make some suggestions?
任何人都可以提出一些建议吗?
采纳答案by Tim Schmelter
You can use LINQto group all items by the chunk size and create new Arrays afterwards.
您可以使用LINQ按块大小对所有项目进行分组,然后创建新的数组。
// build sample data with 1200 Strings
string[] items = Enumerable.Range(1, 1200).Select(i => "Item" + i).ToArray();
// split on groups with each 100 items
String[][] chunks = items
.Select((s, i) => new { Value = s, Index = i })
.GroupBy(x => x.Index / 100)
.Select(grp => grp.Select(x => x.Value).ToArray())
.ToArray();
for (int i = 0; i < chunks.Length; i++)
{
foreach (var item in chunks[i])
Console.WriteLine("chunk:{0} {1}", i, item);
}
Note that it's not necessary to create new arrays(needs cpu cycles and memory). You could also use the IEnumerable<IEnumerable<String>>when you omit the two ToArrays.
请注意,没有必要创建新数组(需要 CPU 周期和内存)。您也可以在IEnumerable<IEnumerable<String>>省略两个时使用ToArrays。
Here's the running code: http://ideone.com/K7Hn2
这是运行代码:http: //ideone.com/K7Hn2
回答by Asif Mushtaq
You can use Skip()and Take()
您可以使用Skip()和Take()
string[] items = new string[]{ "a", "b", "c"};
string[] chunk = items.Skip(1).Take(1).ToArray();
回答by fenix2222
Use LINQ, you can use Take() and Skip() functions
使用 LINQ,可以使用 Take() 和 Skip() 函数
回答by Habib
string[] amzProductAsins = GetProductAsin();;
List<string[]> chunks = new List<string[]>();
for (int i = 0; i < amzProductAsins.Count; i += 100)
{
chunks.Add(amzProductAsins.Skip(i).Take(100).ToArray());
}
回答by Chris Gessler
Array.Copy has been around since 1.1 and does an excellent job of chunking arrays.
Array.Copy 从 1.1 开始就已经存在,并且在分块数组方面做得非常出色。
string[] buffer;
for(int i = 0; i < source.Length; i+=100)
{
buffer = new string[100];
Array.Copy(source, i, buffer, 0, 100);
// process array
}
And to make an extension for it:
并对其进行扩展:
public static class Extensions
{
public static T[] Slice<T>(this T[] source, int index, int length)
{
T[] slice = new T[length];
Array.Copy(source, index, slice, 0, length);
return slice;
}
}
And to use the extension:
并使用扩展名:
string[] source = new string[] { 1200 items here };
// get the first 100
string[] slice = source.Slice(0, 100);
Update: I think you might be wanting ArraySegment<>No need for performance checks, because it simply uses the original array as its source and maintains an Offset and Count property to determine the 'segment'. Unfortunately, there isn't a way to retrieve JUST the segment as an array, so some folks have written wrappers for it, like here: ArraySegment - Returning the actual segment C#
更新:我认为您可能想要ArraySegment<>不需要性能检查,因为它只是使用原始数组作为其源并维护一个 Offset 和 Count 属性来确定“段”。不幸的是,没有办法只将段作为数组检索,所以有些人为它编写了包装器,如下所示:ArraySegment - Returning the actual Segment C#
ArraySegment<string> segment;
for (int i = 0; i < source.Length; i += 100)
{
segment = new ArraySegment<string>(source, i, 100);
// and to loop through the segment
for (int s = segment.Offset; s < segment.Array.Length; s++)
{
Console.WriteLine(segment.Array[s]);
}
}
Performance of Array.Copy vs Skip/Take vs LINQ
Array.Copy 与 Skip/Take 与 LINQ 的性能
Test method (in Release mode):
测试方法(在Release模式下):
static void Main(string[] args)
{
string[] source = new string[1000000];
for (int i = 0; i < source.Length; i++)
{
source[i] = "string " + i.ToString();
}
string[] buffer;
Console.WriteLine("Starting stop watch");
Stopwatch sw = new Stopwatch();
for (int n = 0; n < 5; n++)
{
sw.Reset();
sw.Start();
for (int i = 0; i < source.Length; i += 100)
{
buffer = new string[100];
Array.Copy(source, i, buffer, 0, 100);
}
sw.Stop();
Console.WriteLine("Array.Copy: " + sw.ElapsedMilliseconds.ToString());
sw.Reset();
sw.Start();
for (int i = 0; i < source.Length; i += 100)
{
buffer = new string[100];
buffer = source.Skip(i).Take(100).ToArray();
}
sw.Stop();
Console.WriteLine("Skip/Take: " + sw.ElapsedMilliseconds.ToString());
sw.Reset();
sw.Start();
String[][] chunks = source
.Select((s, i) => new { Value = s, Index = i })
.GroupBy(x => x.Index / 100)
.Select(grp => grp.Select(x => x.Value).ToArray())
.ToArray();
sw.Stop();
Console.WriteLine("LINQ: " + sw.ElapsedMilliseconds.ToString());
}
Console.ReadLine();
}
Results (in milliseconds):
结果(以毫秒为单位):
Array.Copy: 15
Skip/Take: 42464
LINQ: 881
Array.Copy: 21
Skip/Take: 42284
LINQ: 585
Array.Copy: 11
Skip/Take: 43223
LINQ: 760
Array.Copy: 9
Skip/Take: 42842
LINQ: 525
Array.Copy: 24
Skip/Take: 43134
LINQ: 638
回答by fubo
回答by Daniel
You can use List.GetRange:
您可以使用List.GetRange:
for(var i = 0; i < source.Count; i += chunkSize)
{
List<string> items = source.GetRange(i, Math.Min(chunkSize, source.Count - i));
}
Although not at fast as Array.Copy, I think it looks cleaner:
虽然不如 Array.Copy 快,但我认为它看起来更干净:
var list = Enumerable.Range(0, 723748).ToList();
var stopwatch = new Stopwatch();
for (int n = 0; n < 5; n++)
{
stopwatch.Reset();
stopwatch.Start();
for(int i = 0; i < list.Count; i += 100)
{
List<int> c = list.GetRange(i, Math.Min(100, list.Count - i));
}
stopwatch.Stop();
Console.WriteLine("List<T>.GetRange: " + stopwatch.ElapsedMilliseconds.ToString());
stopwatch.Reset();
stopwatch.Start();
for (int i = 0; i < list.Count; i += 100)
{
List<int> c = list.Skip(i).Take(100).ToList();
}
stopwatch.Stop();
Console.WriteLine("Skip/Take: " + stopwatch.ElapsedMilliseconds.ToString());
stopwatch.Reset();
stopwatch.Start();
var test = list.ToArray();
for (int i = 0; i < list.Count; i += 100)
{
int length = Math.Min(100, list.Count - i);
int[] c = new int[length];
Array.Copy(test, i, c, 0, length);
}
stopwatch.Stop();
Console.WriteLine("Array.Copy: " + stopwatch.ElapsedMilliseconds.ToString());
stopwatch.Reset();
stopwatch.Start();
List<List<int>> chunks = list
.Select((s, i) => new { Value = s, Index = i })
.GroupBy(x => x.Index / 100)
.Select(grp => grp.Select(x => x.Value).ToList())
.ToList();
stopwatch.Stop();
Console.WriteLine("LINQ: " + stopwatch.ElapsedMilliseconds.ToString());
}
Results in milliseconds:
结果以毫秒为单位:
List<T>.GetRange: 1
Skip/Take: 9820
Array.Copy: 1
LINQ: 161
List<T>.GetRange: 9
Skip/Take: 9237
Array.Copy: 1
LINQ: 148
List<T>.GetRange: 5
Skip/Take: 9470
Array.Copy: 1
LINQ: 186
List<T>.GetRange: 0
Skip/Take: 9498
Array.Copy: 1
LINQ: 110
List<T>.GetRange: 8
Skip/Take: 9717
Array.Copy: 1
LINQ: 148
回答by Joel
General recursive extension method:
一般递归扩展方法:
public static IEnumerable<IEnumerable<T>> SplitList<T>(this IEnumerable<T> source, int maxPerList)
{
var enumerable = source as IList<T> ?? source.ToList();
if (!enumerable.Any())
{
return new List<IEnumerable<T>>();
}
return (new List<IEnumerable<T>>() { enumerable.Take(maxPerList) }).Concat(enumerable.Skip(maxPerList).SplitList<T>(maxPerList));
}
回答by Francesco
If you have an array to be divided but the division has the rest with this simple solution you can share the elements missing into the various "chunks" equally. In my solution the chunks are linked as a long string but you can easily change that.
如果您有一个要划分的数组,但除法以外的其余部分都可以使用这个简单的解决方案,您可以将缺少的元素平均分配到各个“块”中。在我的解决方案中,块链接为一个长字符串,但您可以轻松更改它。
public static string[] SplitArrey(string[] ArrInput, int n_column)
{
string[] OutPut = new string[n_column];
int NItem = ArrInput.Length; // total elements
int ItemsForColum = NItem / n_column; // n elements for each chunk
int _total = ItemsForColum * n_column; // Count the equal elements
int MissElement = NItem - _total; // Count missing element
int[] _Arr = new int[n_column];
for (int i = 0; i < n_column; i++)
{
int AddOne = (i < MissElement) ? 1 : 0;
_Arr[i] = ItemsForColum + AddOne;
}
int offset = 0;
for (int Row = 0; Row < n_column; Row++)
{
for (int i = 0; i < _Arr[Row]; i++)
{
OutPut[Row] += ArrInput[i + offset] + " "; // <- Here to change how the strings are linked
}
offset += _Arr[Row];
}
return OutPut;
}

