Using Concat to concatenate array of strings

4

I was looking at strings and that they are immutable and can not be added to them in pain under penalty of being too slow.

The recommendation is to use StringBuilder . But I also saw that there is a version of Concat () that accepts an array.

Would not it be the case to use it?

    
asked by anonymous 20.03.2017 / 14:45

1 answer

6

Probably what you read was a "good practice" (which I am a critic). I myself fall into this bullshit when I write because we do not always have the time to explain all the details, but if the person accepts someone's statement without a context, he / she is only following the "good practices" and may not have the expected result, as that can be the opposite and become a bad practice.

In fact, StringBuilder is recommended when you have to add multiple strings into one. But if this operation is the only one and you do not have to do other actions in the loop then you do not have to use StringBuilder , even because I think Concat() uses StringBuilder internally, so it gets a code one liner .

But let's be sure and make a benchmark :

using System;
using static System.Console;
using System.Diagnostics;
using System.Text;

public class Program {
    const int Limit = 100000;
    static int[] dataInt = new int[Limit];
    static string[] dataString = new string[Limit];

    public static void Main() {
        for (int i = 0; i < Limit; i++) {
            dataInt[i] = i;
            dataString[i] = i.ToString();
        }
        Time(ConcatenationInt);
        Time(JunctionInt);
        Time(BuilderInt);
        Time(AdditionInt);
        Time(ConcatenationString);
        Time(JunctionString);
        Time(BuilderString);
        Time(AdditionString);
    }

    static void Time(Func<int> action) {
        var sw = Stopwatch.StartNew();
        int result = action();
        sw.Stop();
        WriteLine($"{result} - {sw.ElapsedTicks:000,000,000} - {action.Method.Name}");
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

    static int AdditionInt() {
        var tmp = "";
        for (int i = 0; i < Limit; i++) {
            tmp += dataInt[i];
        }
        return tmp.Length;            
    }

    static int AdditionString() {
        var tmp = "";
        for (int i = 0; i < Limit; i++) {
            tmp += dataString[i];
        }
        return tmp.Length;
    }

    static int ConcatenationInt() => string.Concat(dataInt).Length;

    static int ConcatenationString() => string.Concat(dataString).Length;

    static int JunctionInt() => string.Join("", dataInt).Length;

    static int JunctionString() => string.Join("", dataString).Length;

    static int BuilderInt() {
        var tmp = new StringBuilder();
        for (int i = 0; i < Limit; i++) {
            tmp.Append(dataInt[i]);
        }
        return tmp.Length;            
    }

    static int BuilderString() {
        var tmp = new StringBuilder();
        for (int i = 0; i < Limit; i++) {
            tmp.Append(dataString[i]);
        }
        return tmp.Length;            
    }
}

See working on .NET Fiddle . And at Coding Ground . Also I put it in GitHub for future reference .

Ideally, you should run the test on your machine without anything affecting execution. Tests in shared environments like the ones used above are not valid. I tried to minimize the effect of GC, but there is no way around this restricted memory environment.

The conclusion you can draw is that if the concatenation is good, the join is too, and the string construct is an almost as good option, only the individual addition is tragic .

The code for Concat() can be seen and it does something up a bit smarter than StringBuilder .

    
20.03.2017 / 14:50