3

I want something similar to String.Join(separator_string, list_of_strings) but for byte arrays.

I need it because I am implementing a file format writer, and the specification says

"Each annotation must be encoded as UTF-8 and separated by the ASCII byte 20."

Then I would need something like:

byte separator = 20;
List<byte[]> encoded_annotations;

joined_byte_array = Something.Join(separator, encoded_annotations);
heltonbiker
  • 26,657
  • 28
  • 137
  • 252
  • 3
    It sounds like you should just join all the strings using `\u0014` and then convert the whole lot into a byte array using UTF-8 at the end. – Jon Skeet Mar 16 '15 at 17:20
  • 1
    @JonSkeet I was prepared to some suggestion like this, which I might end up implementing. But anyway, I would like to keep my question: how I am supposed to join byte arrays, using some other byte array as separator, for arbitrary arrays (not convertible to/from string)? – heltonbiker Mar 16 '15 at 17:27
  • Are you sure your `20` is / is not exactly one SPACE / `" "`? Just build your string of annotations, eseparated by Spaces as a regular C# string and write it to UTF8. – DrKoch Mar 16 '15 at 17:27
  • @DrKoch the specification also mentions bytes `21` and `0` elsewhere, each one to be used as separator for Timesamped Annotation Lists (which is the complete structure to be serialized). And by the way, the space character is byte `32` according to the ASCII table, isn't it? – heltonbiker Mar 16 '15 at 17:28

3 Answers3

3

I don't believe there's anything built in, but it's easy enough to write. Here's a generic version, but you could make it do just byte arrays easily enough.

public static T[] Join<T>(T separator, IEnumerable<T[]> arrays)
{
    // Make sure we only iterate over arrays once
    List<T[]> list = arrays.ToList();
    if (list.Count == 0)
    {
        return new T[0];
    }
    int size = list.Sum(x => x.Length) + list.Count - 1;
    T[] ret = new T[size];
    int index = 0;
    bool first = true;
    foreach (T[] array in list)
    {
        if (!first)
        {
            ret[index++] = separator;
        }
        Array.Copy(array, 0, ret, index, array.Length);
        index += array.Length;
        first = false;
    }
    return ret;
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
1

I ended up using this, tuned to my specific case of a separator consisting of one single byte (instead of an array of size one), but the general idea would apply to a separator consisting of a byte array:

public byte[] ArrayJoin(byte separator, List<byte[]> arrays)
{
    using (MemoryStream result = new MemoryStream())
    {
        byte[] first = arrays.First();
        result.Write(first, 0, first.Length);

        foreach (var array in arrays.Skip(1))
        {
            result.WriteByte(separator);
            result.Write(array, 0, array.Length);
        }

        return result.ToArray();
    }
}
heltonbiker
  • 26,657
  • 28
  • 137
  • 252
1

You just need to specify the desired type for the join command.

String.join<byte>(separator_string, list_of_strings);
Hadi
  • 100
  • 1
  • 11