0

I have a 3 dimensional char array initialized as such:

char[,,] cube = new char[10, 10, 10];

It's completely filled and I want to convert its contents to a single string. My current method is this:

for (int z = 0; z < 10; z++) {
    for (int y = 0; y < 10; y++) {
        for (int x = 0; x < 10; x++) {
            build += cube[z, y, x];
        }
    }
}

Attempting to do build = new string(cube) gives an error:
cannot convert from 'char[*,*,*]' to 'char*'

The for loops are incredibly fast, completing in less than a millisecond on my setup (from 1500 to 4000 ticks). Wondering if a single line method exists that will accomplish the same thing that these nested for loops are doing?

EDIT:
This code will only be used once in the entire program, so I don't need something reusable.

CocoaMix86
  • 69
  • 1
  • 9

4 Answers4

3

LINQ is your friend.

A multidimensional array implements IEnumerable but sadly apparently not IEnumerable<T>. So first we need to get an IEnumerable<T> to be able to make full use of LINQ. Luckily, we know in this case, that every item in that multidimensional array is of typechar, we just need to tell that to the compiler.

Next, to create a string, there is a convenient constructor, that accepts a char[]. And getting a char[] from an IEnumerable<char> is just one ToArray() away.

Put that together and you get:

using System.Linq;

var build = new string(cube.OfType<char>().ToArray());
Corak
  • 2,688
  • 2
  • 21
  • 26
2

This is easier than you think:

public static String FlattenToString(this char[,,] array)
{
    var builder = new StringBuilder();

    foreach(var @char in array)
    {
        builder.Append(@char);
    }

    return builder.ToString();
}

var cube = new char[2,2,2];

cube[0,0,0] = 'a';
cube[0,0,1] = 'b';
cube[0,1,0] = 'c';
cube[0,1,1] = 'd';
cube[1,0,0] = 'e';
cube[1,0,1] = 'f';
cube[1,1,0] = 'g';
cube[1,1,1] = 'h';

Console.WriteLine(cube.FlattenToString());

Prints out abcdefgh.

V0ldek
  • 9,623
  • 1
  • 26
  • 57
  • While the end result does do it in "one line", adding the Method here `FlattenToString` adds more lines than the nested loop does. – CocoaMix86 Sep 08 '18 at 16:19
2
string build = string.Concat(cube.Cast<char>());

Probably not needed in your case, but a much faster alternative is copying to char[] :

//var cube = new[, ,] { { { 'a', 'b' }, { 'c', 'd' } }, { { 'e', 'f' }, { 'g', 'h' } } };
char[] temp = new char[cube.Length];
Buffer.BlockCopy(cube, 0, temp, 0, temp.Length * sizeof(char));
string build = new string(temp);
Slai
  • 22,144
  • 5
  • 45
  • 53
  • @Corak true for earlier .NET versions. .NET 4 has `IEnumerable` overload – Slai Sep 08 '18 at 16:53
  • sorry, I thought you were using `new string`, too. But you're actually using `string.Concat`, which *does* accept `IEnumerable`. – Corak Sep 08 '18 at 16:58
  • About the performance... looks like`ToArray()` fills an internal Buffer, basically an array with starting size of 4, while `Concat` uses a `StringBuilder`, also basically an array but with starting size of 16. Both doubling the size when needed and doing `Array.Copy`, which is probably the most expensive operation in there. So `ToArray()` would have to do that two times more (4 => 8 => 16) -- then it really comes to the question, which one has more overhead. The Buffer keeps the `char` as `char`, while `Concat` does `ToString` on each char... that'd need very carefully done benchmarking. – Corak Sep 08 '18 at 17:13
  • 1
    `string.Concat(IEnumerable)` uses a cached `StringBuilder` instance for up to 360 characters, but seems to be a bit slower on average for 1000 characters. My guess for the inconsistent results is mostly the branch mispredictions from the if statements. My tests with 1000 `char[,,]` are about 2 ms for the LINQ answers, about 10 ns with `new StringBuilder(cube.Length)` or unsafe `char*`, and only about 1 ns with `Buffer.BlockCopy` (~1000+ times faster than LINQ!) – Slai Sep 08 '18 at 20:36
1
char[,,] cube = new char[10, 10, 10];
                for (int z = 0; z < 10; z++)
                {
                    for (int y = 0; y < 10; y++)
                    {
                        for (int x = 0; x < 10; x++)
                        {
                            cube[z, y, x] = (char)(65+x);
                        }
                    }
                }
/* Just Filling data in array*/    
                var s1 = cube.OfType<char>().ToList();
                string s = string.Join("",s1);
Sumit raj
  • 821
  • 1
  • 7
  • 14