Click here to Skip to main content
11,413,548 members (72,013 online)
Click here to Skip to main content
Alternative Article

Efficient string concatenation algorithm implements String.Join() method

, 23 Sep 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
Alternative solution that demonstrates performance improvement using String.Join() (extends original one:"StringBuilderPlus Improves Upon StringBuilder").

Introduction

This article describes an alternative algorithm of string concatenation using the String.Join() method instead of the StringBuilder object Append() method and provides performance estimates of both algorithms.

Background

The following code snippets implements two string concatenation algorithms:

  1. Using the StringBuilder object Append() method.
  2. Using the String.Join() static method.

In both test settings, the array of strings (1,000,000 items) was pre-populated, thus the stopwatch counts only the elapsed time spent on the actual string concatenation (please note that in the original article the loop includes a i.ToString() conversion, which is included in the elapsed time estimates, thus affecting the result and distorting the performance statistics). Also, a stopwatch object provides much more accurate time measurement (it is a part of the System.Diagnostics object library).

The Insert() method addressing the Prefixing/Suffixing issue as described in the original article is off consideration provided that "in-real-life" scenarios it's possible to just reverse the order of operation if necessary and then apply the Append() method, which is more efficient than Insert() (based on the performance estimates included in the original article).

The main goal of the article and corresponding test settings is to introduce more efficient solution for string concatenation utilizing String.Join() static method instead of StringBuilder Append() method, and to provide empirically obtained performance estimates.

Using the code

Both algorithms apply the following sample string delimiter:

", " 
Listing 1. Sample string concatenation using StringBuilder Append() method
#region String Concatenation Using StringBuilder.Append() method
/// <summary>
/// StringBuilder.Append() method performance estimate
/// </summary>
/// <param name="LoopCounter">Int64</param>
/// <returns>double</returns>
public static double ConcatenateUsingAppend(Int64 LoopCounter)
{
    StringBuilder _sb = new StringBuilder();

    // array of string to concatenate
    string[] _arTemp = new string[LoopCounter];

    // populate array with sample strings
    for (Int64 i = 0; i < LoopCounter; i++)
    {
        _arTemp[i] = i.ToString();
    }

    // stopwatch obj (ref: System.Diagnostics)
    Stopwatch _sw = new Stopwatch();

    // start count ticks
    _sw.Start();

    // concatenate using Append()
    for (Int64 i = 0; i < LoopCounter; i++)
    {
        _sb.Append(_arTemp[i]);
        _sb.Append(", ");
    }

    // result string
    string _result = _sb.ToString();

    // stop count
    _sw.Stop();

    // duration measured in ticks
    Int64 _ticks = _sw.ElapsedTicks;

    // stopwatch frequency in kHZ
    double _frequency = Stopwatch.Frequency;

    // time per tick
    double _secPerTick = 1 / _frequency;

    // duration in msec (rounded)
    return Math.Round((1000 * _ticks * _secPerTick), 1);
}
#endregion
Listing 2. Sample string concatenation using String.Join() method
/// <summary>
/// String.Join() method performance estimate
/// </summary>
/// <param name="LoopCounter">Int64</param>
/// <returns>double</returns>
public static double StringJoin(Int64 LoopCounter)
{
            
    // array of string to concatenate
    string[] _arTemp = new string[LoopCounter];

    // populate array with sample strings
    for (Int64 i = 0; i < LoopCounter; i++)
    {
        _arTemp[i] = i.ToString();
    }

    // stopwatch obj (ref: System.Diagnostics)
    Stopwatch _sw = new Stopwatch();

    // start count ticks
    _sw.Start();

    // get result string using String.Join()
    string _result = String.Join(", ", _arTemp);

    // stop count
    _sw.Stop();

    // duration measured in ticks
    Int64 _ticks = _sw.ElapsedTicks;

    // stopwatch frequency in kHZ
    double _frequency = Stopwatch.Frequency;

    // time per tick
    double _secPerTick = 1 / _frequency;

    // duration in msec (rounded)
    return Math.Round((1000 * _ticks * _secPerTick),1);
}
Listing 3. Test project implemented as Win Form contains single Form, Button1 and two labels; Button1 click event
private void button1_Click(object sender, EventArgs e)
{
    Int64 _iterations = 1000000; // 1 million
    label1.Text = "Duration using Append(), msec: " + ConcatenateUsingAppend(_iterations).ToString();
    label2.Text = "Duration using String.Join(), msec: " + StringJoin(_iterations).ToString();
}

Points of interest

Empirically obtained results demonstrate almost three times performance improvement by utilizing the static String.Join() method (elapsed time about 36 msec for 1,000,000 strings) vs. StringBuilder object Append() method (took about 100 msec for the same test settings).

String.Join and String.Split methods (.NET)

Thanks to reader's input and thoughtful comments, I found it relevant to elaborate further on the usage of String.Join and also, String.Split, as some of our fellow programmers may be not quite familiar with these methods.

The static method String.Join has been a part of .NET Framework since version 1.1, though in most current forms it was introduced in V.2.0 (see ref [1]) as shown below (C# syntax):

public static string Join (string separator, string[] value)

Responding to the comments: separator (the first parameter) can be an empty string, thus pertinent to the example in Listing 2, the concatenation line can be written like the following (joining all strings together):

string _result = String.Join(String.Empty, _arTemp);

but even more efficient way pertinent to this just concatenation case (without delimiters) will be to use the String.Concat method as described later in the article.

Serialization/De-serialization

The String.Join method can be used, for example, in order to serialize the array of strings converting it to a single delimited one. Another operator String.Split does exactly the opposite (see ref [2]), returning the array of strings extracted from a single delimited one. Important to mention that if the original array of strings contain empty strings or blank spaces, then the String.Join() method will still add specified delimiters, so the reverse operation based on String.Split() will return the array of the same structure and content.

It's relevant to mention (even though this is typically a quite known fact) that the "+" operator when applied to strings is very inefficient performance-wise, thus the Append() method is recommended in general for that type of string operations. But for a special purpose of concatenating strings array with a specified delimiter added as described in the article, the String.Join() method outperforms the "+" operator and the Append() method as well.

Prefixing/Suffixing is simple with the String.Join() method

If prefixing (which is semantically equal to "inserting a delimiter before") is required for all elements of the string array, then the specified prefix should be added only once in front of just the first array's element (index of 0) before running the String.Join() concatenation; the rest of the code remains the same. Correspondingly, the suffix should be added (if necessary) to the last element of the string array before applying the String.Join() method.

String.Concat method

As discussed above, the String.Join() method provides the ability to concatenate an array of strings with an added prefix, suffix, or both (they can all be included in a separator string along with the actual delimiting char). But in case strings delimiting is not required, then another static method namely: String.Concat() [3] can do the job even more efficiently than String.Join(): the additional performance boost was calculated as approx. 20% vs. String.Join() applying the same test settings (run time about 29 ms vs. 36 ms), and just replacing a single line of code with the following one:

string _result = String.Concat(_arTemp);

History

  • Posted on: Sep. 22, 2012.
  • Updated on Sep. 23, 2012.

References

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

DrABELL
President Infosoft International Inc
United States United States
Dr. A. Bell has 20+ years of Software and Electrical Engineering experience: Win/Web veteran, published 300+ articles and authored 37 inventions, credited for 10+ Enterprise level projects (>250k code lines); currently focused on .NET/WPF, C#, HTML5, jQuery, SQL, 'Big Data', AI, Speech Tech and Mobile apps. He participated in App Innovation Contest (AIC 2102/2013) with several winning submissions. Sample projects/pubs follow:
  1. Edumatter M12: School Math Calculators and Equation Solvers (contest winner)
  2. Engineering Calculator VOLTA-2013 (contest winner)
  3. WebTV Project: Embedded YouTube Player (Goog #1 YouTube API for ASP.NET)
  4. Online 3 Fractions Calculator (#1 on Goog)
  5. Top-100 Digital Cameras (powered by iMark-DCAM rating engine)
  6. Engineering Calculator VOLTA-814 for Windows
  7. Pericles™ TTS-14 Text-to-Speech Synthesizer (Win)
  8. Semaphon™ SP-300 semantic phone number converter (Win)
  9. PaydayNY-2015 Payroll Tax Calculator (Win)
  10. 'Find Job Agency' Online Interactive Map (Microsoft Bing technology)
Follow on   Twitter

Comments and Discussions

 
GeneralMy vote of 5 Pin
Espen Harlinn at 16-Oct-12 22:46
mvpEspen Harlinn16-Oct-12 22:46 
GeneralRe: My vote of 5 Pin
DrABELL at 17-Oct-12 2:55
memberDrABELL17-Oct-12 2:55 
QuestionYou should mention that Pin
FatCatProgrammer at 23-Sep-12 9:15
memberFatCatProgrammer23-Sep-12 9:15 
AnswerRe: You should mention that Pin
DrABELL at 23-Sep-12 11:51
memberDrABELL23-Sep-12 11:51 
GeneralRe: You should mention that Pin
FatCatProgrammer at 24-Sep-12 6:07
memberFatCatProgrammer24-Sep-12 6:07 
GeneralRe: You should mention that Pin
DrABELL at 24-Sep-12 6:47
memberDrABELL24-Sep-12 6:47 
GeneralMy vote of 5 Pin
Akram El Assas at 23-Sep-12 8:10
memberAkram El Assas23-Sep-12 8:10 
GeneralRe: My vote of 5 Pin
DrABELL at 23-Sep-12 10:06
memberDrABELL23-Sep-12 10:06 
SuggestionRe: My vote of 5 Pin
Dan Randolph at 23-Sep-12 12:04
memberDan Randolph23-Sep-12 12:04 
GeneralRe: My vote of 5 Pin
DrABELL at 23-Sep-12 12:42
memberDrABELL23-Sep-12 12:42 
GeneralMy vote of 5 Pin
Dan Randolph at 23-Sep-12 7:30
memberDan Randolph23-Sep-12 7:30 
GeneralRe: My vote of 5 Pin
DrABELL at 23-Sep-12 10:13
memberDrABELL23-Sep-12 10:13 
GeneralMy vote of 4 Pin
cjb110 at 23-Sep-12 1:52
membercjb11023-Sep-12 1:52 
GeneralRe: My vote of 4 Pin
DrABELL at 23-Sep-12 3:13
memberDrABELL23-Sep-12 3:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150427.1 | Last Updated 23 Sep 2012
Article Copyright 2012 by DrABELL
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid