Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to split an array into chunks of specific size? [closed]

Tags:

arrays

c#

split

Afternoon,

I need to split an array into smaller "chunks".

I am passing over about 1200 items, and need to split these into easier to handle arrays of 100 items each, which I then need to process.

Could anyone please make some suggestions?

like image 686
thatuxguy Avatar asked Jun 26 '12 12:06

thatuxguy


People also ask

What function split an array into chunks?

Example 2: Split Array Using splice() In the above program, the while loop is used with the splice() method to split an array into smaller chunks of an array. In the splice() method, The first argument specifies the index where you want to split an item.

How do you divide an array into multiple parts?

Splitting the Array Into Even Chunks Using slice() Method The easiest way to extract a chunk of an array, or rather, to slice it up, is the slice() method: slice(start, end) - Returns a part of the invoked array, between the start and end indices.

How do you split an array into a smaller array?

Divide and Chunk an Array Into Smaller Arrays JavaScript comes with the Array#splice method. The splice method removes items from an array and returns them as a new array. This way, you can remove the number of items from the source array until it's empty.

Which function is used to divide an array into smaller evenly size array?

concat(split(array. slice(size), cols-1)) .


2 Answers

Array.Copy has been around since 1.1 and does an excellent job of chunking arrays.

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<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

Test method (in Release mode):

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 
like image 77
Chris Gessler Avatar answered Oct 08 '22 06:10

Chris Gessler


You can use LINQ to group all items by the chunk size and create new Arrays afterwards.

// 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.

Here's the running code: http://ideone.com/K7Hn2

like image 45
Tim Schmelter Avatar answered Oct 08 '22 06:10

Tim Schmelter