1

I have a byte array and I would like to return sequential chuncks (in the form of new byte arrays) of a certain size.

I tried:

originalArray = BYTE_ARRAY
var segment = new ArraySegment<byte>(originalArray,0,640); 
byte[] newArray = new byte[640];
for (int i = segment.Offset; i <= segment.Count; i++)
{
newArray[i] = segment.Array[i];
}

Obviously this only creates an array of the first 640 bytes from the original array. Ultimately, I want a loop that goes through the first 640 bytes and returns an array of those bytes, then it goes through the NEXT 640 bytes and returns an array of THOSE bytes. The purpose of this is to send messages to a server and each message must contain 640 bytes. I cannot garauntee that the original array length is divisible by 640.

Thanks

5
  • First, a note: that ArraySegment is still using the same buffer as the original array. This is often exactly what you might intend, but it's not what you're describing in the rest of your question. Commented Sep 8, 2018 at 5:50
  • Yes, to answer this properly we need to know (a) do you need to make an actual copy of the original data, or will referencing the original data in chunks be enough? (b) Can you do with an IEnumerable<byte> for the chunks, or does it have to be an array? (c) What version of C# and .Net are you using? The answers to these questions will determine the most performant solution. Commented Sep 8, 2018 at 8:39
  • a) needs to be a copy b) it needs to be a byte array c) it’s and asp.net core mcc app Commented Sep 8, 2018 at 8:45
  • Also what happens to the leftover bytes if the buffer isn't a multiple of 640? Are they just ignored, or are they padded to 640 bytes with zeros and sent, or something else? Commented Sep 8, 2018 at 8:51
  • I am assuming it’s just ignored. I am trying to write audio to a websocket as per this documentation “developer.nexmo.com/voice/voice-api/guides/websockets” which requires a message size of 640 bytes Commented Sep 8, 2018 at 8:54

3 Answers 3

2

if speed isn't a concern

var bytes = new byte[640 * 6];

for (var i = 0; i <= bytes.Length; i+=640)
{
   var chunk = bytes.Skip(i).Take(640).ToArray();
   ...
}

Alternatively you could use

Span

Span<byte> bytes = arr; // Implicit cast from T[] to Span<T>

...

slicedBytes = bytes.Slice(i, 640);

BlockCopy

Note this will probably be the fastest of the 3

var chunk = new byte[640]
Buffer.BlockCopy(bytes, i, chunk, 0, 640);
Sign up to request clarification or add additional context in comments.

Comments

0

If you truly want to make new arrays from each 640 byte chunk, then you're looking for .Skip and .Take

Here's a working example (and a repl of the example) that I hacked together.

using System;
using System.Linq;
using System.Text;
using System.Collections;
using System.Collections.Generic;

class MainClass {
public static void Main (string[] args) {
        // mock up a byte array from something
        var seedString = String.Join("", Enumerable.Range(0, 1024).Select(x => x.ToString()));
        var byteArrayInput = Encoding.ASCII.GetBytes(seedString);

        var skip = 0;
        var take = 640;
        var total = byteArrayInput.Length;

        var output = new List<byte[]>();

        while (skip + take < total) {
            output.Add(byteArrayInput.Skip(skip).Take(take).ToArray());
            skip += take;
        }

        output.ForEach(c => Console.WriteLine($"chunk: {BitConverter.ToString(c)}"));
    }
}

It's really probably better to actually use the ArraySegment properly --unless this is an assignment to learn LINQ extensions.

Comments

0

You can write a generic helper method like this:

public static IEnumerable<T[]> AsBatches<T>(T[] input, int n)
{
    for (int i = 0, r = input.Length; r >= n; r -= n, i += n)
    {
        var result = new T[n];
        Array.Copy(input, i, result, 0, n);
        yield return result;
    }
}

Then you can use it in a foreach loop:

byte[] byteArray = new byte[123456];

foreach (var batch in AsBatches(byteArray, 640))
{
    Console.WriteLine(batch.Length); // Do something with the batch.
}

Or if you want a list of batches just do this:

List<byte[]> listOfBatches = AsBatches(byteArray, 640).ToList();

If you want to get fancy you could make it an extension method, but this is only recommended if you will be using it a lot (don't make an extension method for something you'll only be calling in one place!).

Here I've changed the name to InChunksOf() to make it more readable:

public static class ArrayExt
{
    public static IEnumerable<T[]> InChunksOf<T>(this T[] input, int n)
    {
        for (int i = 0, r = input.Length; r >= n; r -= n, i += n)
        {
            var result = new T[n];
            Array.Copy(input, i, result, 0, n);
            yield return result;
        }
    }
}

Which you could use like this:

byte[] byteArray = new byte[123456];

// ... initialise byteArray[], then:

var listOfChunks = byteArray.InChunksOf(640).ToList();

[EDIT] Corrected loop terminator from r > n to r >= n.

3 Comments

How will this handle the remainder of the original byte array if the length of the original byte array is not divisible by 640? I simply want to disregard the final “batch” it doesn’t equal 640 bytes.
@HarryStuart That's exactly what this will do - any leftover bytes will be ignored.
Fantastic, I’ll test out the code either later tonight or tomorrow morning

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.