What is the best way to copy a StringBuilder? - c#

What is the best way (performance wise) to instantiate a new StringBuilder from another one? (Copy-Ctor).
I don't want to pass via an immutable string as the underneath data is very big.
so the below is valid, but not wanted.
StringBuilder newSB = new StringBuilder(oldSB.ToString());
I want something like
StringBuilder newSB = new StringBuilder(oldSB);
But this is not supported.

There’s an overload of Append for other StringBuilder instances:
var newSB = new StringBuilder(oldSB.Length);
newSB.Append(oldSB);

Related

A way to parse multidimensional string array to list c#

If need an simple way to parse this string:
string a = "[[[
[-118.407, 33.749],
[-118.407, 33.749],
[-118.407, 33.749],
[-118.407, 33.749],
[-118.407,33.749]
]]]"
to something like: List<List<List<List<double>>>>
you can use your code fragments diectly with the right method:
var r = System.Text.Json.JsonSerializer.Deserialize< List<List<List<List<double>>>> >(a);
System.Text.Json is the new .net Core serializer, for older platforms use Newtonsoft:
var r = Newtonsoft.Json.JsonConvert.DeserializeObject< List<List<List<List<double>>>> >(a);
But I think you may have 1 level of List<> too many. Experiment.

extend Stringbuilder to append array

Still new to the extension methods. According to this guide, it is still unclear to me how I can append an array just like appending a string with Append(). Can anyone provide me with a small example?
int a = 2;
object obj = XXXXX;
StringBuilder sb = new StringBuilder();
sb.Append(a);
sb.Append(obj);
Basically the type of obj is unknown it could be int[], char[]..., I am trying to reuse Append() to make it more generalized to handle array types so the
sb.ToString()
will output the whole thing I have appended

StringBuilder vs string constructor - the character

I just saw a code like
StringBuilder result = new StringBuilder();
for (int i = 0; i < n; i++)
{
result.Append("?");
}
return result.ToString();
I know that concatenating with StringBuilder is considered faster (and does not create new instance of a string on every append). But is there any reason we would not prefer to write
return new string('?', n)
instead?
But is there any reason we would not prefer to write return new string("?", n) instead
The only reason I can think of is unfamiliarity of the developer with the existence of this string constructor. But for people familiar with it, no, there is no reason to not use it.
Also you probably meant:
return new string('?', n)
The main reason not to use new string("?", n) is that no such constructor exists and it won't compile. However, there is absolutely no reason not to use new string('?', n), and I fully encourage you to do so.

Performance considerations for String and StringBuilder - C#

All,
For the string string s = "abcd", does string w = s.SubString(2) return a new allocated String object i.e. string w = new String ("cd") internally or a String literal?
For StringBuilder, when appending string values and if the size of the StringBuilder needs to be increased, are all the contents copied over to a new memory location or simply the pointers to each of the earlier String value are reassigned to the new location?
String is immutable, so any operation that "changes" the string, will in effect return a new string. This includes SubString and all other operations on String, including those that does not change the length (such as ToLower() or similar).
StringBuilder contains internally a linked list of chunks of characters. When it needs to grow, a new chunk is allocated and inserted at the end of the list, and data is copied here. In other words, the whole StringBuilder buffer will not be copied on an append, only the data you are appending. I double-checked this against the Framework 4 reference sources.
For the string string s = "abcd", does string w = s.SubString(2) return a new allocated String object? Yes
For StringBuilder, when appending string values and if the size of the StringBuilder needs to be increased, are all the contents copied over to a new memory location? Yes
Any change in String small or large results in a new String
If you are going to make large numbers of edits to a string it better to do this via StringBuilder.
From MSDN:
You can use the StringBuilder class instead of the String class for operations that make multiple changes to the value of a string. Unlike instances of the String class, StringBuilder objects are mutable; when you concatenate, append, or delete substrings from a string, the operations are performed on a single string.
Strings are immutable objects so every time you had to make changes you create a new instance of that string. The substring method does not change the value of the original string.
Regards.
Difference between the String and StringBuilder is an important concept which makes the difference when an application has to deal with the editing of a high number of Strings.
String
The String object is a collection of UTF-16 code units represented by a System.Char object which belong to the System namespace. Since the value of this objects are read-only, the entire object String has defined as immutable. The maximum size of a String object in memory is 2 GB, or about 1 billion characters.
Immutable
Being immutable means that every time a methods of the System.String is used, a new sting object is created in memory and this cause a new allocation of space for the new object.
Example:
By using the string concatenation operator += appears that the value of the string variable named test change. In fact, it create a new String object, which has a different value and address from the original and assign it to the test variable.
string test;
test += "red"; // a new object string is created
test += "coding"; // a new object string is created
test += "planet"; // a new object string is created
StringBuilder
The StringBuilder is a dynamic object which belong to the System.Text namespace and allow to modify the number of characters in the string that it encapsulates, this characteristic is called mutability.
Mutability
To be able to append, remove, replace or insert characters, A StringBuilder maintains a buffer to accommodate expansions to the string. If new data is appended to the buffer if room is available; otherwise, a new, larger buffer is allocated, data from the original buffer is copied to the new buffer, and the new data is then appended to the new buffer.
StringBuilder sb = new StringBuilder("");
sb.Append("red");
sb.Append("blue");
sb.Append("green ");
string colors = sb.ToString();
Performances
In order to help you better understand the performance difference between String and StringBuilder, I created the following example:
Stopwatch timer = new Stopwatch();
string str = string.Empty;
timer.Start();
for (int i = 0; i < 10000; i++) {
str += i.ToString();
}
timer.Stop();
Console.WriteLine("String : {0}", timer.Elapsed);
timer.Restart();
StringBuilder sbr = new StringBuilder(string.Empty);
for (int i = 0; i < 10000; i++) {
sbr.Append(i.ToString());
}
timer.Stop();
Console.WriteLine("StringBuilder : {0}", timer.Elapsed);
The output is
Output
String : 00:00:00.0706661
StringBuilder : 00:00:00.0012373

Is StringBuilder really faster than Aggreggate?

string c = tmpArr[0].Aggregate(string.Empty, (current, m) => current + (m.Name + " "));
StringBuilder sb = new StringBuilder();
foreach (Mobile m in tmpArr[0])
sb.Append(m.Name + " ");
sb.ToString();
which of those two is faster? aggregate certainly is cleaner, but is it fast or is it the same as doing
foreach(Mobile m in tmpArr[0])
c += m.Name + " ";
what I really would like to do is something like string.Join(",",tmpArr[0]), but I don't want it to concat their ToString values, just their Names, how would I do that best?
my problem with not using string.Join is I would actually have to do something like this:
string separator = "";
StringBuilder sb = new StringBuilder();
foreach (Mobile m in tmpArr[0])
{
separator = ", ";
sb.Append(separator + m.Name);
}
If you append strings in a loop (c += m.Name + " ";) you are causing lots of intermediate strings to be created; this causes "telescopic" memory usage, and puts extra load on GC. Aggregate, mixed with the fluent-API of StringBuilder can help here - but as would looping with StringBuilder. It isn't Aggregate that is important: it is not creating lots of intermediate strings.
For example, I would use:
foreach (Mobile m in tmpArr[0])
sb.Append(m.Name).Append(" ");
even fewer ;p
And for a similar example using StringBuilder in Aggregate:
string c = tmpArr[0].Aggregate(new StringBuilder(),
(current, m) => current.Append(m.Name).Append(" ")).ToString();
I don't want it to concat their ToString values, just their Names, how would I do that best?
string.Join(",",tmpArr[0].Select(t => t.Name).ToArray())
But most of the time It. Just. Doesn't. Matter!
As string is Immutable, add operation has performance cost. This is what the StringBuilder is mainly designed for, it acts like "Mutable" String. I haven't done much benchmarking for the speed, but for memory optimizations StringBuilder is definitely better.
Aggregate runs an anonymous method against each item in the IEnumerable. This method is passed to the System-defined Func<> delegate which returns an out parameter.
It's basically like running a function that does the appending as many times.
So allocation/deallocation on the stack for the method calls etc certainly has more overhead than running a simple for/foreach loop
So, in my opinion the second method would be faster.
Aggregate itself is not the problem. The problem is you are concatenating strings in a loop. When you concatenate two strings with + operator, a new place must be allocated in memory and the two strings are copied into it. So if you use the + five times, you actually create five new strings. That's why you should use StringBuilder or Join which avoid this.
If you want to use Join along with linq for better readability, you still can, just don't use Aggregate but something like Select and ToArray.
Something like this?
string joined = string.Join(",", myItems.Select(x => x.Name).ToArray());

Categories

Resources