Giliweed
Giliweed

Reputation: 5177

Control the index of an byte[] array

Is it possible to control the index position in a byte[] array? In the following code I expect the return value of value1 enters in the first seven bytes in join and the return value of value2 enters in the 8 9 10 11 position sequentially. But this is not happening. The first seven bytes are lost because the index is in 0 position always. How to control the index position?

static void Main(string[] args)
    {
        byte[] join = new byte[15];
        join = value1(); //seven byte enters. 
        join = value2(); //next four byte enters.
                               // 'join' should now have eleven bytes. 
        string a = Encoding.UTF8.GetString(join);
        Console.WriteLine(a);
        Console.ReadLine();
    }

    public static byte[] value1() 
    {

        string first = "welcome";
        byte[] f = Encoding.UTF8.GetBytes(first);
        return f;// seven byte returning.

    }

    public static byte[] value2() 
    {
        string second = "home";
        byte[] s = Encoding.UTF8.GetBytes(second);
        return s;//four byte returning.
    }

I know the code can be reorganize using Array.Copy() or Buffer.BlockCopy(). But these two methods are time consuming if the code runs 100,000 times or more. I'm looking forward to avoid these two methods and get the return values directly inside join.

---Thanks

Upvotes: 0

Views: 165

Answers (3)

Jim Mischel
Jim Mischel

Reputation: 133995

There is a way to do what you want, but you have to be careful. This GetBytes overload lets you specify the byte array into which the bytes will be copied, and the index at which they will be copied. So, in your example, it would look like this:

    byte[] join = new byte[15];
    int ix = 0;
    ix = ix + Encoding.UTF8.GetBytes(first, 0, first.Length, join, ix);
    ix = ix + Encoding.UTF8.GetBytes(second, 0, second.Length, join, ix);
    string a = Encoding.UTF8.GetString(join, 0, ix);

The ix variable here keeps track of the total number of bytes that are encoded.

You have to be careful here to allocate enough bytes in your join array, and you have to keep track of the number of bytes encoded because with UTF-8 (and many other encodings) a single character could require multiple bytes.

You'll also want to see the GetString overload that lets you specify the starting position in the array and the number of bytes.

If you want to write methods that do this like your value1 and value2 methods, you'll have to pass the byte array and the array index to the methods. And those methods will have to return the number of bytes they encoded, or they'll have to add that value to the index and return the new index.

Upvotes: 4

digEmAll
digEmAll

Reputation: 57210

value1 and value2 methods returns a byte array, while you presumably want to append the values to the existing join array.

You can use Array.Copy (or Buffer.BlockCopy) to put the returned values inside join array :

var v1 = value1(); //seven byte returned. 
var v2 = value2(); //next four byte returned.
var join = new byte[v1.Length + v2.Length];

// copy v1 at index 0 of join
Array.Copy(v1, 0, join, 0, v1.Length); 
// copy v2 at index v1.Length of join
Array.Copy(v2, 0, join, v1.Length, v2.Length); 

EDIT :

I did a small benchmark to test the performances of the proposed methods, and here's the result (with 6 millions of repetions for each method) :

Benchmark results (6000000 repetitions) :
JoinCodeUsingArrayCopy       : 4076021 ticks (1304 ms)
JoinCodeUsingSetItems        : 4873634 ticks (1559 ms)
JoinCodeUsingList            : 8729925 ticks (2793 ms)
JoinCodeUsingBufferBlockCopy : 3665075 ticks (1172 ms)

Benchmark code here.

As you can see Array.Copy/Buffer.BlockCopy are the fastest methods, even if the method using list is not much much slower (we're talking about 1.5 second of difference on 6 million iterations after all).
Probably I would go for the list method because is the cleanest since it does not require to work directly with offsets/start indexes.

Upvotes: 3

Selman Genç
Selman Genç

Reputation: 101681

Instead of assigning items of your array, you are throwing away the new byte[15] and assigning it to new array. You can try using List<byte> first then convert it to an array:

var byteList = new List<byte>(15);

byteList.AddRange(value1());
byteList.AddRange(value2());

byte[] join = byteList.ToArray();

Another alternative is to create an extension method for your array, something like this:

public static void SetItems<T>(this T[] source, int startIndex, IEnumerable<T> items)
{
     // I omitted the checks (index, length, null etc.) but you should add them
     int i = startIndex;

     foreach(var item in items)
          source[i++] = item;
}

Then call it:

byte[] join = new byte[15];
join.SetItems(0, value1());
join.SetItems(4, value2());

This should be faster than first option because it doesn't create a list but it requires you to know the startIndex, in this case it shouldn't be a problem..

Upvotes: 3

Related Questions