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.

5
  • Simple create an extension method and it will be single line Commented Sep 8, 2018 at 16:03
  • 3
    you mean something like var build = new string(cube.OfType<char>().ToArray());? Commented Sep 8, 2018 at 16:06
  • Closest I could get: foreach (char s in cube) {build += s;} Commented Sep 8, 2018 at 16:11
  • @Corak, nice one! Commented Sep 8, 2018 at 16:13
  • Almost the same as this. Read Jon's answer. Commented Sep 8, 2018 at 16:17

4 Answers 4

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());
Sign up to request clarification or add additional context in comments.

1 Comment

LINQ comes to the rescue again. This is perfect. Thank you!
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.

1 Comment

While the end result does do it in "one line", adding the Method here FlattenToString adds more lines than the nested loop does.
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);

4 Comments

@Corak true for earlier .NET versions. .NET 4 has IEnumerable<T> overload
sorry, I thought you were using new string, too. But you're actually using string.Concat, which does accept IEnumerable<char>.
About the performance... looks likeToArray() 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.
string.Concat(IEnumerable<T>) 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!)
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);

2 Comments

You don't need explicit ToList(). string.Join works on IEnumerable<string>
@MrinalKamboj yeah thanx.

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.